Safeguard
Security Guides•

PyYAML safe_load vs load: what changes for untrusted YAML

yaml.load can build arbitrary Python objects, while yaml.safe_load cannot. When to use each, how custom classes work, and what to change in old code.

Safeguard Security Team
3 min read

For YAML from any source you do not control, use yaml.safe_load. The PyYAML documentation says yaml.load is as powerful as pickle.load and may call any Python function, so it is not safe on untrusted input. safe_load limits results to simple types.

What the two functions do

yaml.load(stream, Loader=...) takes a loader class. The full Loader supports all predefined tags and, in the docs' words, "may construct an arbitrary Python object." A YAML document can therefore contain tags that make the parser build and call objects of the document author's choosing.

yaml.safe_load(stream) uses SafeLoader, which recognizes only standard YAML tags and does not construct class instances. You get dictionaries, lists, strings, numbers, booleans, dates and null.

import yaml

with open("config.yml") as f:
    config = yaml.safe_load(f)

"But it is just our config file"

A config file feels trusted until you ask who can change it. Think about:

  • Files read from a repository that outside contributors can open pull requests against.
  • Config uploaded through an admin screen.
  • Files fetched from a URL or object store.
  • Fixtures and test data that tools load automatically.

If the answer is anyone other than the people who already have code execution on that host, use safe_load. The cost of switching is almost always zero.

What if you need your own classes

Sometimes people reach for the full loader because they want YAML to produce their own objects. The docs describe a way to keep safe loading: derive your class from yaml.YAMLObject and set its yaml_loader to yaml.SafeLoader. That makes the class an explicit, reviewed exception rather than opening the door to every Python tag.

A simpler pattern is to load plain data with safe_load and then construct your objects in code after validating the fields. Validation in your own code is easier to test than tag handling in the parser.

Fixing old code

Search your codebase for these patterns:

  • yaml.load( without a loader argument.
  • yaml.load(..., Loader=yaml.Loader) or yaml.Loader anywhere.
  • yaml.load_all( and yaml.full_load(.

Replace them with safe_load and safe_load_all, run your tests, and see which fail. A failure usually means the file uses Python specific tags, which is worth a conversation on its own.

Do not stop at the parser

Safe parsing means the YAML cannot run code during loading. It does not mean the values are valid. After safe_load, check types, ranges and allowed keys before using them, especially for anything that ends up in a file path, shell command or SQL string.

Safeguard's dependency scanning and reachability analysis can show whether a YAML library version in your tree has known issues and whether your code reaches the affected function. A free scan is at gold.safeguard.sh/scan.

Quick check

Is yaml.load with SafeLoader the same as yaml.safe_load?

Functionally close, since safe_load uses SafeLoader. The safe_load name makes the intent obvious in review and removes the chance of picking the wrong loader.

Does safe_load validate my config?

No. It only prevents arbitrary object construction. You still need to check the values.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.