Skip to content

PyYAML yaml.load(input) Deprecation

Ingy döt Net edited this page Sep 22, 2020 · 9 revisions

This page explains the PyYAML 5.1+ deprecation of the plain yaml.load(input) function. See Footnotes.

Use of PyYAML's yaml.load function without specifying the Loader=... parameter, has been deprecated. In PyYAML version 5.1+, you will get a warning, but the function will still work. See How to Disable the Warning below.

Before PyYAML 5.1+, the PyYAML.load function could be easily exploited to call any Python function. That means it could call any system command using os.system(). Here is a trivial example:

python -c 'import yaml; yaml.load("!!python/object/new:os.system [echo EXPLOIT!]")'

Why is this deprecated?

PyYAML's load function has been unsafe since the first release in May 2006. It has always been documented that way in bold type: PyYAMLDocumentation. PyYAML has always provided a safe_load function that can load a subset of YAML without exploit.

In 2017, a CVE was filed against PyYAML because it was capable of being exploited on untrusted input using the load function, even though PyYAML was intentionally designed and documented to work that way from the start. The CVE seems to suggest that load should use safe_load by default. Since safe_load only handles a subset of YAML, and PyYAML has been a very popular Python package for over a decade, this change is not feasible.

YAML is cross-programming language, data serialization language. PyYAML is an implementation of YAML that provides human friendly (plain text) data serialization for Python. Pickle is Python's native (binary) data serialization format. Pickle is also unsafe, and documented loudly as such. The author of PyYAML intentionally made it Pickle compatible.

Since load cannot break backwards compatibility to call safe_load, the maintainers of PyYAML decided to simply deprecate the plain usage of load, and require that the user intentionally declare the Loader they desired. There are 4 loaders to choose from. See Below...

The load function was also made much safer by disallowing the execution of arbitrary functions by the default loader (FullLoader).

NOTE The FullLoader loader class and full_load function (the current default for load) should be avoided for now. New exploits in 5.3.1 were found in July 2020. These exploits will be addressed in the next release, but if further exploits are found then FullLoader may go away.

How to Disable the Warning

If you are simply using Python software that issues the "load() deprecation" warning, you should notify the authors of that software about it, so they can make and release the proper adjustments. One way to control/disable the warning is with the PYTHONWARNINGS environment variable:

PYTHONWARNINGS=ignore::yaml.YAMLLoadWarning

You can read more about PYTHONWARNINGS here.

If you are the author/maintainer of the Python code that is triggering the warning, the best way to stop getting the warning is to specify the Loader= argument like so:

yaml.load(input, Loader=yaml.FullLoader)

The current Loader choices are:

  • BaseLoader

    Only loads the most basic YAML. All scalars are loaded as strings.

  • SafeLoader

    Loads a subset of the YAML language, safely. This is recommended for loading untrusted input.

  • FullLoader

    Loads the full YAML language. Avoids arbitrary code execution. This is currently (PyYAML 5.1+) the default loader called by yaml.load(input) (after issuing the warning).

    WARNING: As of pyyaml-5.3.1 there are still trivial exploits. Do not use this on untrusted data for now.

  • UnsafeLoader (also called Loader for backwards compatability)

    The original Loader code that could be easily exploitable by untrusted data input.

You may also use one of the shortcut "sugar" methods:

  • yaml.safe_load
  • yaml.full_load (See FullLoader WARNING above)
  • yaml.unsafe_load

If you are the author/maintainer of software that uses third party modules that trigger this warning, first make sure that their usage is safe for your application. Make sure they are aware of the warning. Then you can "globally" disable the warning with:

yaml.warnings({'YAMLLoadWarning': False})

Footnotes

This page will be kept up to date with the latest information about the load() deprecation, usage and warnings.

The warning messages point to https://msg.pyyaml.org/load, which in turn should redirect you to here.