By NHI Mgmt Group Editorial TeamDomain: Cyber SecuritySource: SemgrepPublished October 22, 2025

TL;DR: yaml.Loader is unsafe in all released versions of PyYAML, while yaml.safe_load remains safe in every version and yaml.load, yaml.full_load, and their _all variants are only known-safe after 5.4, according to Semgrep. The practical lesson is that version-specific API behaviour, not documentation alone, should drive deserialization rules and code scanning.


At a glance

What this is: Semgrep tested PyYAML versions and concluded that loader safety varies sharply by API, with yaml.Loader unsafe in every released version and yaml.safe_load consistently safe.

Why it matters: For IAM and NHI practitioners, deserialization flaws can expose secrets, credentials, and control-plane access paths, so loader choice and version-aware scanning affect both application security and identity governance.

👉 Read Semgrep's analysis of PyYAML loader safety and deserialization risk


Context

Python YAML deserialization is a security boundary, not just a parsing convenience. Unsafe loaders can convert crafted input into arbitrary Python objects, which turns a data-handling routine into a code-execution path. In programmes that manage secrets, configuration, or workload identities, that can become an identity issue as soon as YAML-backed automation touches tokens, keys, or service credentials.

Semgrep’s analysis is useful because it separates API myths from version-specific behaviour. The key question for practitioners is not whether a library has ever been vulnerable, but which call patterns remain dangerous in the versions actually deployed. That is a familiar governance problem in identity and adjacent controls: tooling has to follow runtime reality, not stale assumptions.


Key questions

Q: What should security teams do when YAML parsing might expose code execution risk?

A: Treat YAML parsing as a security boundary and default to safe_load for any untrusted content. Then inventory every code path that uses broader loaders, especially in CI/CD, automation, and services that can touch secrets or workload credentials. The goal is to remove ambiguity at the input boundary before it becomes an execution path.

Q: Why do unsafe YAML loaders create broader risk than a normal parsing bug?

A: Unsafe loaders can instantiate attacker-controlled Python objects during deserialization, which turns crafted input into a possible code execution path. That matters because the resulting compromise can extend beyond the application into secrets, automation, and infrastructure access. In other words, the parser can become an entry point to the control plane.

Q: How do teams know whether a PyYAML finding is actually exploitable?

A: Check the exact library version, the loader class in use, and whether the input source is trusted. A finding that is severe in one release may be non-exploitable in another, so remediation should be based on tested behaviour, not on the function name alone. That is the only reliable way to separate real risk from stale alerts.

Q: What is the difference between yaml.safe_load and broader PyYAML loaders?

A: yaml.safe_load restricts input to basic data types and blocks object construction behaviour that can be abused for code execution. Broader loaders allow more expressive parsing, but that flexibility creates risk when input is not fully trusted. Use the safe path unless you have a narrow, reviewed need for richer deserialization.


Technical breakdown

Why yaml.load and unsafe loaders create code execution risk

PyYAML deserialization becomes dangerous when the parser is allowed to instantiate Python objects from attacker-controlled tags. In that mode, a YAML document can reference constructors or object factories that execute code during object creation, which moves the problem beyond data validation into arbitrary execution. Semgrep’s testing confirms that the risky surface is not just one function name but a family of loaders and variants that permit unsafe object construction. The core control issue is whether the library is allowed to interpret structure as executable behaviour, rather than treating input as plain data.

Practical implication: scan for unsafe loader variants and treat any code path that deserializes untrusted YAML as a potential execution boundary.

Why version-specific behaviour matters for PyYAML rules

PyYAML’s API changed over time, which means a static rule that flags every yaml.load call can produce both false positives and false confidence. The Semgrep post shows why security guidance must account for library version, loader class, and function variant together. After 5.4, known exploit payloads no longer worked against yaml.load and yaml.full_load in the tested cases, but older versions still mattered for exposed codebases. For security teams, this is the same governance challenge seen in identity controls when lifecycle state and implementation details determine whether a control is actually effective.

Practical implication: make scanner rules version-aware so remediation effort matches the deployed PyYAML release, not just the API name.

Why safe_load is the durable default for YAML parsing

safe_load limits deserialization to simple Python-native types and blocks the object construction behaviour that makes unsafe loaders exploitable. That makes it the only broadly durable choice when the input source is not fully trusted. Semgrep’s conclusion is operationally important because it shifts the question from patching around exploit payloads to enforcing a safe parsing contract. In practice, the safest design is to assume YAML inputs can be adversarial until proven otherwise, especially in systems that ingest configuration from users, automation, or third-party pipelines.

Practical implication: standardise on safe_load for all untrusted YAML and only allow broader loaders behind explicit, reviewed exceptions.


Threat narrative

Attacker objective: The attacker aims to turn a YAML parsing step into remote code execution on the target system.

  1. Entry occurs when an attacker supplies crafted YAML to an application that deserializes untrusted input with an unsafe loader.
  2. Escalation happens when the parser constructs attacker-influenced Python objects or invokes embedded constructors during deserialization.
  3. Impact follows when the resulting code execution gives the attacker control of the application host or access to secrets and downstream systems.

NHI Mgmt Group analysis

Unsafe deserialization is an access-control problem disguised as a parsing bug. When a library can turn attacker-controlled input into executable objects, the application has effectively delegated trust at the wrong boundary. That matters to identity programmes because configuration files, automation manifests, and pipeline inputs often carry credentials, tokens, and endpoint metadata. Practitioners should treat deserialization policy as part of the control plane, not as a developer convenience.

Version-aware rule tuning is now a core security governance task. Semgrep’s analysis shows that blanket detections can be too noisy when API behaviour changes across releases. Security teams need detection logic that understands library version, function variant, and loader class so findings map to actual exploitability. That approach reduces alert fatigue and gives remediation teams a defensible priority order.

YAML parsing sits inside the wider secrets and workload boundary. In modern delivery pipelines, YAML often configures jobs that retrieve secrets, call APIs, or assume workload identity. A deserialization flaw can therefore become a path to NHI abuse, not just application compromise. Secrets-to-execution window: once untrusted YAML can instantiate objects, the path from configuration ingestion to secret exposure becomes a governance failure, not a coding mistake. Practitioners should audit every YAML ingress point that can influence privileged automation.

Static analysis works best when it mirrors actual exploit conditions. The article’s testing approach is a useful model for security engineering because it validates claims against runtime behaviour rather than documentation alone. That is especially relevant for libraries with long vulnerability histories, where outdated assumptions linger in codebases and rulesets. Teams should use empirical validation to decide which findings are truly actionable and which merely reflect legacy risk.

Safe defaults need to be enforced as policy, not preference. The post’s clearest operational lesson is that safe_load should be the default for untrusted content, with broader loaders treated as exceptional and reviewable. Identity and platform teams should make that a standard part of secure development and pipeline hardening. Practitioners should encode the safe path so developers do not have to remember the nuance every time they parse YAML.

What this signals

Secrets-to-execution risk is a lifecycle problem, not just a code-quality issue. When YAML parsers sit inside build pipelines, deployment automation, or configuration ingestion, the boundary between application security and NHI governance disappears. Teams should watch for any process where untrusted config can influence tokens, certificates, or service accounts, because that is where parser bugs become identity incidents.

The operational signal is whether your controls distinguish trusted from untrusted deserialization paths. If every YAML call is treated the same, noisy findings will mask the few that can actually reach privileged automation. Aligning detection with runtime context, and validating it against the deployed package version, is the difference between manageable risk and alert fatigue.

For identity-heavy programmes, this is a cue to map where configuration data can mutate into access. That includes CI/CD jobs, GitOps workflows, and internal tooling that consumes YAML before calling APIs or assuming workload identity. Teams that have already formalised lifecycle management for machines will be better placed to contain that risk.


For practitioners

  • Standardise on safe_load for untrusted YAML Require yaml.safe_load in application code, CI jobs, and automation that processes external or semi-trusted YAML. Ban unsafe loaders by policy unless a security review documents the exact trusted input boundary.
  • Tune detection rules to PyYAML version and loader class Update SAST and Semgrep rules so they distinguish yaml.Loader, UnsafeLoader, and the post-5.4 behaviour of yaml.load and yaml.full_load. This keeps high-confidence findings from being buried under legacy noise.
  • Inventory YAML ingestion points that touch secrets or identity data Map every service that parses YAML before it can reach credentials, tokens, deployment manifests, or workload identity settings. Prioritise the paths where parser compromise could lead to secret exposure or control-plane access.
  • Test exploitability against the versions you actually run Replicate the article’s version-and-payload testing approach for any library with a checkered security history. Validate whether the deployed release is truly vulnerable before spending time on remediation that may no longer be necessary.

Key takeaways

  • Unsafe YAML deserialization is dangerous because it can become code execution, not just bad parsing.
  • PyYAML safety depends on both version and loader choice, so detection rules must match runtime reality.
  • Practical governance starts with safe_load by default, version-aware scanning, and tight control over YAML paths that touch secrets or automation identities.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

MITRE ATT&CK and OWASP Non-Human Identity Top 10 address the attack and risk surface, while NIST CSF 2.0, NIST SP 800-53 Rev 5 and CIS Controls v8 set the governance and control requirements practitioners need to meet.

FrameworkControl / ReferenceRelevance
MITRE ATT&CKTA0002 , ExecutionUnsafe deserialization can convert input into code execution.
NIST CSF 2.0PR.DS-1Parsing untrusted YAML affects data handling and protection at ingestion points.
NIST SP 800-53 Rev 5SI-10Input validation is central when attacker-controlled YAML reaches deserializers.
CIS Controls v8CIS-16 , Application Software SecuritySecure coding controls are directly relevant to deserialization hardening.
OWASP Non-Human Identity Top 10NHI-03Secrets and automation identities can be exposed when YAML reaches privileged workflows.

Review YAML ingress points that can touch secrets, tokens, or workload identity and remove unnecessary privilege.


Key terms

  • Unsafe Deserialization: Unsafe deserialization happens when software reconstructs objects from untrusted data in a way that can trigger code execution or state corruption. In practice, the risk is not the file or message itself, but the fact that the parser is allowed to invoke behaviour while rebuilding the object.
  • Safe Loader: A safe loader is a parsing mode that limits input to basic data types and blocks the object instantiation features that make deserialization exploitable. In PyYAML, safe_load is the practical default when the source of YAML cannot be fully trusted.
  • Loader Class: A loader class defines how a parser interprets YAML content and which features it will allow during deserialization. In PyYAML, the choice between Loader, SafeLoader, FullLoader, and UnsafeLoader determines whether input stays data or can influence executable object creation.
  • Version-Aware Detection: Version-aware detection means tuning security rules to the exact software release in use, not just the API name. It is essential when library behaviour changes over time, because a finding may be exploitable in one version and harmless in another.

What's in the full article

Semgrep's full post covers the operational detail this post intentionally leaves for the source:

  • The version-by-version test matrix showing which PyYAML APIs were vulnerable and when
  • The Semgrep rule changes used to separate true positives from SafeLoader false positives
  • The payload-testing approach that practitioners can adapt for other libraries with a history of unsafe deserialization
  • The exact rule logic behind alerting on unsafe_load, Loader, UnsafeLoader, and C variants

👉 Semgrep's full post covers the test matrix, payload methods, and rule updates in detail

Deepen your knowledge

The NHI Foundation Level course, the industry's only accredited NHI security programme, covers NHI governance, secrets management, workload identity, and identity lifecycle basics. It gives practitioners a shared control vocabulary for reducing risk across automation, access, and credential handling.
NHIMG Editorial Note
Published by the NHIMG editorial team on August 2, 2026.
NHI Mgmt Group — the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org