Coordinated Disclosure Timeline
- 2023-10-10: Opened public issue
- 2023-10-10: Report sent through GitHub PVR
- 2023-11-21: Merged PR including a partial fix and documentation update.
Summary
MkDocs is vulnerable to an unsafe deserialization when parsing configuration files.
Note: After a private discussion with the maintainer, we agreed that a complete fix was not possible given the nature of the project. Instead, there were some partial fixes and documentation updates done on the project.
Project
MkDocs
Tested Version
Details
Unsafe deserialization of configuration files (GHSL-2023-208
)
MkDocs uses the YAML format for configuration files such as mkdocs.yml
and mkdocs_theme.yml
. They are loaded using mkdocs.utils.yaml_load
(see how mkdocs.yml
and mkdocs_theme.yml
are loaded), which, if not provided a loader
, will use yaml.Loader
, known to be able to instantiate arbitrary constructors.
# https://github.com/mkdocs/mkdocs/blob/00b648f0884244a139f034554b59a032113176f6/mkdocs/utils/yaml.py#L124
def get_yaml_loader(loader=yaml.Loader, config: MkDocsConfig | None = None):
"""Wrap PyYaml's loader so we can extend it to suit our needs."""
class Loader(loader):
"""
Define a custom loader derived from the global loader to leave the
global loader unaltered.
"""
# ...
return Loader
def yaml_load(source: IO | str, loader: type[yaml.BaseLoader] | None = None) -> dict[str, Any]:
"""Return dict of source YAML file using loader, recursively deep merging inherited parent."""
loader = loader or get_yaml_loader()
try:
result = yaml.load(source, Loader=loader)
except yaml.YAMLError as e:
raise exceptions.ConfigurationError(
f"MkDocs encountered an error parsing the configuration file: {e}"
)
This issue was found using the Unsafe deserialization CodeQL query for python.
Impact
This issue may lead to Remote Code Execution
.
Proof of concept
- Install an existing theme such as dracula:
pip install mkdocs-dracula-theme
- Replace
mkdocs_theme.yml
(mkdocs_dracula_theme/mkdocs_theme.yml
) with the following contents: ``` !!python/object/apply:os.popen - touch /tmp/pwned ```
- Run mkdocs and check for the existence of
pwned
in/tmp
.
Resources
Note
Even though the unsafe deserialization of mkdocs.yml
has already been discussed and noted as a Won’t Fix given the downsides for the project, there’s still a huge risk in the unsafe deserialization of mkdocs_theme.yml
. An attacker may be able to hijack a popular theme, or widely-spread one, and gain access to CI/CD systems and/or developer machines.
Credit
This issue was discovered and reported by GHSL team member @jorgectf (Jorge Rosillo).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2023-208
in any communication regarding this issue.