classification
Title: [Security] logging.config should not use eval()
Type: security Stage:
Components: Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Mariatta Nosy List: Mariatta, loganasherjones, vinay.sajip, vstinner, willingc, xtreak
Priority: normal Keywords:

Created on 2019-02-18 11:29 by vstinner, last changed 2019-05-06 15:25 by loganasherjones.

Messages (5)
msg335820 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-02-18 11:29
For logging "handlers", _install_handlers() of logging.config uses eval():

def _install_handlers(cp, formatters):
    """Install and return handlers"""
    hlist = cp["handlers"]["keys"]
    ...
    for hand in hlist:
        ...
        klass = section["class"]
        try:
            klass = eval(klass, vars(logging))
        except (AttributeError, NameError):
            klass = _resolve(klass)
        args = section.get("args", '()')
        args = eval(args, vars(logging))
        kwargs = section.get("kwargs", '{}')
        kwargs = eval(kwargs, vars(logging))
        h = klass(*args, **kwargs)
        ...
    ...
    return handlers

eval() is considered harmful regarding security: it executes arbitrary Python code.

Would it be possible to rewrite this function without eval?

I'm not sure of the format of the handler "class". Is it something like "module.submod.attr"? If yes, maybe a regex to validate the class would help? Maybe a loop using getattr() would be safer?

Maybe ast.literal_eval() would be enough? At least for args and kwargs?

$ python3
Python 3.7.2 (default, Jan 16 2019, 19:49:22) 
>>> import ast

# Legit positional and keyword arguments are accepted
>>> ast.literal_eval("(1, 2)")
(1, 2)
>>> ast.literal_eval("{'x': 1, 'y': 2}")
{'x': 1, 'y': 2}

# eval() executes arbitrary Python code
>>> eval('__import__("os").system("echo hello")')
hello
0

# literal_eval() doesn't execute system()
>>> ast.literal_eval('__import__("os").system("echo hello")')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.7/ast.py", line 91, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib64/python3.7/ast.py", line 90, in _convert
    return _convert_signed_num(node)
  File "/usr/lib64/python3.7/ast.py", line 63, in _convert_signed_num
    return _convert_num(node)
  File "/usr/lib64/python3.7/ast.py", line 55, in _convert_num
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x7f60a400c780>
msg335821 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-02-18 11:33
The issue has been reported by Alexandre D'Hondt to th PSRT.

I only selected Python 3.8 version, since currently, logging.config explicitly *documents* that eval() is used. Example:

https://docs.python.org/3/library/logging.config.html#logging.config.listen

This issue is not a security vulnerability: you shouldn't let your users modify your logging configuration.

Alex Gaynor asked: "Does anyone know whether the logging config is considered to be equally privileged to the code using it or not?"

Paul McMillan wrote: "This does not qualify for a CVE. Allowing someone else to configure your logging endpoints would result in significant harm to your app in any language. For instance, in many applications you could turn the log level to debug, and then capture things like database credentials. Additionally, this behavior is extremely clearly documented with a callout warning, and is thus expected behavior."

(Quotes from private PSRT list.)
msg335826 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-02-18 12:20
Some discussion in issue15452 about using ast.literal_eval instead of eval which I think is the similar to this report.
msg335890 - (view) Author: Carol Willing (willingc) * (Python committer) Date: 2019-02-19 06:28
Assigning this to @Mariatta, to be worked on the mentored sprint at PyCon US Cleveland.
msg341527 - (view) Author: Logan Jones (loganasherjones) * Date: 2019-05-06 15:25
I'd like to work on this during the Pycon sprints
History
Date User Action Args
2019-05-06 15:25:07loganasherjonessetnosy: + loganasherjones
messages: + msg341527
2019-02-19 06:28:49willingcsetassignee: Mariatta

messages: + msg335890
nosy: + Mariatta, willingc
2019-02-18 12:20:42xtreaksetnosy: + xtreak
messages: + msg335826
2019-02-18 11:33:49vstinnersetmessages: + msg335821
2019-02-18 11:29:37vstinnersettitle: logging.config should not use eval() -> [Security] logging.config should not use eval()
2019-02-18 11:29:28vstinnercreate