Issue 36022: [Security] logging.config should not use eval() (original) (raw)

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 "", line 1, in 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>

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.)