CVE-2017-18342 — PyYAML default `load` resolves arbitrary tags
PyYAML’s yaml.load() resolved !!python/object and friends
without an explicit safe loader, making any
attacker-controlled YAML a code-execution primitive. The CVE
is the formal advisory; the behaviour predates the CVE by
the better part of a decade. PyYAML 5.1 added a deprecation
warning when Loader= was omitted; PyYAML 6.0 made the
omission a TypeError. Most repos have call sites that
predate either change.
Affected versions
- PyYAML ≤ 3.13 — vulnerable, no warning.
- PyYAML 4.x — never released widely.
- PyYAML 5.1+ — emits a
YAMLLoadWarningwhenLoader=is omitted; still resolves unsafe tags by default. - PyYAML 6.0+ —
yaml.load()raisesTypeErrorwithout an explicitLoader. The behaviour was made safe by removal.
Indicator-of-exposure
Any call site of yaml.load(...) (without Loader=),
yaml.load(..., Loader=yaml.Loader),
yaml.load(..., Loader=yaml.UnsafeLoader), or
yaml.full_load(...) on untrusted input.
Detection:
git grep -n "yaml\\.load\\b\\|yaml\\.full_load\\b\\|Loader=yaml\\.\\(Loader\\|UnsafeLoader\\|FullLoader\\)"
Whether the call is exposed depends on the data flow: attacker-controlled YAML (file upload, HTTP body, partner feed) is exposure; a trusted application config file is not — though the safe shape costs nothing on trusted input either.
Remediation strategy
This CVE has a generic recipe that covers it directly:
- See Classic Vulnerable Defaults → PyYAML
yaml.loadfor the durable fix pattern.
This per-CVE recipe overlays the broader generic recipe with two CVE-specific actions:
- Pin PyYAML to ≥6.0 (or ≥5.1 with
Loader=yaml.SafeLoaderon every call) to lock in the safe-default behaviour at the library level. - Re-scan with the SCA tool to confirm CVE-2017-18342 is no longer reported against the post-fix lockfile.
When to use it
Use this recipe when Python code depends on PyYAML and parses YAML from uploads,
HTTP bodies, partner feeds, CI config, user-edited files, model/tool output, or
other untrusted sources. It is also useful for repositories with older
yaml.load, yaml.full_load, custom loaders, or wrappers around PyYAML.
Use it to combine code-level deserialization remediation with the CVE-specific dependency pin and SCA proof. Do not use it to silently replace custom YAML tag handling without a behavior-preservation review.
Inputs
- Python manifests, lockfiles, constraints, dependency reports, SBOMs, PyYAML version evidence, SCA findings, and package-manager update commands.
- Call sites for
yaml.load,yaml.load_all,yaml.full_load,yaml.full_load_all, unsafeLoader=values, wrappers, helper functions, and custom constructors or resolvers. - Data-flow evidence for YAML sources: uploads, API bodies, partner feeds, config files, CI files, model output, tool output, MCP responses, tests, fixtures, and trusted internal config.
- Existing tests, custom YAML tag behavior, parser compatibility constraints, transitive dependencies that pin PyYAML, and scanner re-scan evidence.
- Related deserialization controls for pickle, object tags, import-time shims, and safe loader policies.
The prompt
You are remediating CVE-2017-18342 (PyYAML default-loader
RCE) in this repository. Output a PR or a TRIAGE.md.
## Step 0 — Inventory
1. List every `yaml.load`, `yaml.full_load`,
`yaml.load(..., Loader=yaml.Loader)`,
`yaml.load(..., Loader=yaml.UnsafeLoader)`,
`yaml.load(..., Loader=yaml.FullLoader)` call.
2. Read the lockfile and confirm the pinned PyYAML version.
## Step 1 — Apply the generic fix pattern
Follow the recipe at
[/prompt-library/general/classic-vulnerable-defaults/pyyaml-load/]
end-to-end. Replace every unsafe call with `yaml.safe_load`,
or install the import-time shim, or both.
## Step 2 — Pin PyYAML
1. Pin PyYAML to ≥6.0 in the lockfile / requirements file.
2. Run the project's test suite to surface any breakage from
the 5.x → 6.x bump.
3. If the project depends on a transitive consumer of
PyYAML <6 (`pip-tools` resolves a downgrade), document
the constraint in the PR body. The agent does not silently
downgrade.
## Step 3 — Verify
1. Re-run the SCA scanner. CVE-2017-18342 must show as fixed
or not present.
2. Add the standard PyYAML safe-load test from the generic
recipe (a payload with `!!python/object/apply:os.system`
raises `yaml.constructor.ConstructorError`).
## Step 4 — Open the PR
- Branch: `remediate/cve-2017-18342-pyyaml`.
- Title: `[Security][CVE-2017-18342] safe_load + pin PyYAML ≥6`.
- Body: per-call-site list, lockfile diff, SCA before/after,
test addition, any downstream pin notes.
- Label: `sec-auto-remediation`.
## Stop conditions
- A transitive dependency requires PyYAML <6 and cannot be
upgraded without a coordinated cross-repo change.
- A custom YAML tag the codebase legitimately uses requires a
non-Safe loader and the agent cannot determine whether the
tag's resolver is itself safe.
## Scope
- Do not bundle unrelated CVEs.
- Do not silently re-pin downstream constraints.
Verification — what the reviewer looks for
- Every call site touched, or shim installed, with a clear rationale per call.
- PyYAML pinned to ≥6.0.
- SCA output shows CVE-2017-18342 cleared.
- Behaviour-preservation test for any custom YAML tag the codebase uses.
Watch for
yaml.load_allandyaml.full_load_all. Same problem, same fix.- Indirect callers. Some libraries ship their own
yaml.load(...)wrapper — fix the library or pin it past the patched version. - PyYAML 6.x parser changes. A handful of edge-case documents parse differently in 6.x (octal-number rules, some boolean shortcuts). Run the project’s tests.
Output contract
Return one of:
- A reviewer-ready PR/change request that inventories every unsafe PyYAML call,
replaces it with
safe_loador a justified safe loader/shim, pins PyYAML to6.0+where compatible, adds exploit-shaped tests, runs the suite, and refreshes SCA evidence. TRIAGE.mdwhen a transitive dependency requires PyYAML<6, a custom YAML tag needs a non-Safe loader whose resolver cannot be reviewed safely, or the required fix needs a coordinated cross-repo change.
The output must list call sites, data sources, loader choice, PyYAML before/after version, lockfile changes, tests added, SCA before/after, custom tag behavior, and residual owners. It must not silently downgrade constraints, leave unsafe loaders on untrusted input, or bundle unrelated CVEs.
References
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2017-18342
- GitHub Advisory: https://github.com/advisories/GHSA-rprw-h62v-c2w7
Related recipes
- Classic Vulnerable Defaults → PyYAML
yaml.load— the durable, tool-agnostic recipe this overlays. - Vulnerable Dependency Remediation — the generic workflow.
- Python pickle — sibling Python deserialization risk.