问题确认 Search before asking
Bug组件 Bug Component
Deploy, Training, Validation
Bug描述 Describe the Bug
Summary
PaddleDetection uses YAML for configuration, but config loading uses PyYAML's
Loader=yaml.Loader (the full loader, which can construct arbitrary Python objects) —
equivalent to yaml.unsafe_load. Loading a crafted config file therefore executes arbitrary
code inside that process.
Locations
# ppdet/core/workspace.py:86-88
def _load_config_with_base(file_path):
with open(file_path) as f:
file_cfg = yaml.load(f, Loader=yaml.Loader) # <- not safe_load
Same pattern (-o k=v command-line overrides; input comes from the command line, see Impact):
ppdet/utils/cli.py:69, :77
deploy/pipeline/cfg_utils.py:30, :38
Root cause
yaml.Loader is not a safe loader: it supports tags such as !!python/object/apply, which let
yaml.load invoke arbitrary Python callables during parsing. The PyYAML docs explicitly recommend
yaml.safe_load (or SafeLoader) for untrusted input.
Steps to reproduce (pure stdlib — no PaddlePaddle/CUDA needed)
import os, tempfile, yaml
p = tempfile.mktemp(suffix=".yml")
with open(p, "w") as f:
f.write('!!python/object/apply:os.system ["touch /tmp/PD_YAML_RCE"]\n')
# ----- equivalent to ppdet/core/workspace.py:88 -----
with open(p) as f:
yaml.load(f, Loader=yaml.Loader)
# ---------------------------------------------------
print("marker exists:", os.path.exists("/tmp/PD_YAML_RCE"))
Expected results
Parsing a config should only build plain data structures; !!python/... tags should be rejected
with an error rather than executing any Python call (i.e. the SafeLoader / safe_load behavior).
Actual results
marker exists: True <- /tmp/PD_YAML_RCE was created; the command executed
Impact and preconditions
PaddleDetection's YAML configs are assets that get shared, downloaded and copied around in ML
workflows:
ppdet/utils/download.py::get_config_path(url) downloads a configs tar and consumes it;
- in practice users routinely use configs provided by others (model zoo, tutorials, configs pushed
by an internal platform).
So if an attacker can get a user to load a crafted config (or tamper with the configs download
source), they get arbitrary code execution at that process's privilege level.
To be precise: a local, self-authored config does not constitute a trust boundary (users run
their own configs), so exploitability depends on whether the config comes from an untrusted source —
which is frequently the case in PaddleDetection's actual usage, especially via the
get_config_path download path above.
Suggested fix
# ppdet/core/workspace.py:88
file_cfg = yaml.load(f, Loader=yaml.SafeLoader) # or yaml.safe_load(f)
Same for ppdet/utils/cli.py:69/77 and deploy/pipeline/cfg_utils.py:30/38.
If specific object construction is genuinely needed, register a controlled constructor explicitly
rather than enabling the full Loader.
复现环境 Environment
- OS: Ubuntu 22.04
- PaddlePaddle: N/A - reproducible at the plain Python + PyYAML level; PaddlePaddle is not needed
- PaddleDetection: local clone, commit b25522a (2026-03-16); also present on develop
- Python: 3.10.12
- PyYAML: any version (reproduces on all)
- CUDA: N/A
- CUDNN: N/A
- GCC: N/A
Bug描述确认 Bug description confirmation
是否愿意提交PR? Are you willing to submit a PR?
问题确认 Search before asking
Bug组件 Bug Component
Deploy, Training, Validation
Bug描述 Describe the Bug
Summary
PaddleDetection uses YAML for configuration, but config loading uses PyYAML's
Loader=yaml.Loader(the full loader, which can construct arbitrary Python objects) —equivalent to
yaml.unsafe_load. Loading a crafted config file therefore executes arbitrarycode inside that process.
Locations
Same pattern (
-o k=vcommand-line overrides; input comes from the command line, see Impact):ppdet/utils/cli.py:69,:77deploy/pipeline/cfg_utils.py:30,:38Root cause
yaml.Loaderis not a safe loader: it supports tags such as!!python/object/apply, which letyaml.loadinvoke arbitrary Python callables during parsing. The PyYAML docs explicitly recommendyaml.safe_load(orSafeLoader) for untrusted input.Steps to reproduce (pure stdlib — no PaddlePaddle/CUDA needed)
Expected results
Parsing a config should only build plain data structures;
!!python/...tags should be rejectedwith an error rather than executing any Python call (i.e. the
SafeLoader/safe_loadbehavior).Actual results
Impact and preconditions
PaddleDetection's YAML configs are assets that get shared, downloaded and copied around in ML
workflows:
ppdet/utils/download.py::get_config_path(url)downloads a configs tar and consumes it;by an internal platform).
So if an attacker can get a user to load a crafted config (or tamper with the configs download
source), they get arbitrary code execution at that process's privilege level.
To be precise: a local, self-authored config does not constitute a trust boundary (users run
their own configs), so exploitability depends on whether the config comes from an untrusted source —
which is frequently the case in PaddleDetection's actual usage, especially via the
get_config_pathdownload path above.Suggested fix
Same for
ppdet/utils/cli.py:69/77anddeploy/pipeline/cfg_utils.py:30/38.If specific object construction is genuinely needed, register a controlled constructor explicitly
rather than enabling the full
Loader.复现环境 Environment
Bug描述确认 Bug description confirmation
是否愿意提交PR? Are you willing to submit a PR?