CVE-2019-20477

9.8 CRITICAL

📋 TL;DR

This vulnerability in PyYAML allows remote code execution through unsafe YAML deserialization. Attackers can exploit the load() and load_all() functions to execute arbitrary commands via the subprocess.Popen class. Any application using vulnerable PyYAML versions to parse untrusted YAML input is affected.

💻 Affected Systems

Products:
  • PyYAML
Versions: 5.1 through 5.1.2
Operating Systems: All operating systems running Python
Default Config Vulnerable: ⚠️ Yes
Notes: Only affects applications using PyYAML's load() or load_all() functions with untrusted input. Safe_load() is not affected.

📦 What is this software?

⚠️ Risk & Real-World Impact

🔴

Worst Case

Full system compromise with remote code execution leading to data theft, ransomware deployment, or complete system takeover.

🟠

Likely Case

Remote code execution allowing attackers to run arbitrary commands, install malware, or pivot to other systems.

🟢

If Mitigated

Limited impact if proper input validation and sandboxing prevent untrusted YAML parsing.

🌐 Internet-Facing: HIGH - Web applications parsing user-supplied YAML are directly exploitable.
🏢 Internal Only: MEDIUM - Internal tools or APIs processing YAML could be exploited by authenticated users.

🎯 Exploit Status

Public PoC: ⚠️ Yes
Weaponized: CONFIRMED
Unauthenticated Exploit: ⚠️ Yes
Complexity: LOW

Exploit code is publicly available and trivial to weaponize. No authentication required if application parses untrusted YAML.

🛠️ Fix & Mitigation

✅ Official Fix

Patch Version: PyYAML 5.2 and later

Vendor Advisory: https://github.com/yaml/pyyaml/blob/master/CHANGES

Restart Required: No

Instructions:

1. Upgrade PyYAML to version 5.2 or later using pip: pip install --upgrade pyyaml>=5.2
2. Verify the upgrade with: pip show pyyaml
3. Test application functionality after upgrade.

🔧 Temporary Workarounds

Replace unsafe load with safe_load

all

Replace all instances of yaml.load() and yaml.load_all() with yaml.safe_load() and yaml.safe_load_all() in code.

# Code change example:
# Replace: data = yaml.load(input)
# With: data = yaml.safe_load(input)

Input validation and sanitization

all

Implement strict input validation to reject untrusted YAML input or sanitize before processing.

# Example validation:
if not trusted_source(yaml_input):
    raise ValueError('Untrusted YAML input rejected')

🧯 If You Can't Patch

  • Implement network segmentation to isolate vulnerable systems
  • Deploy application-level firewalls to block malicious YAML payloads

🔍 How to Verify

Check if Vulnerable:

Check PyYAML version with: python -c "import yaml; print(yaml.__version__)" and verify if between 5.1 and 5.1.2.

Check Version:

python -c "import yaml; print(yaml.__version__)"

Verify Fix Applied:

After upgrade, verify version is 5.2 or higher: python -c "import yaml; print(yaml.__version__)"

📡 Detection & Monitoring

Log Indicators:

  • Unusual process spawns from Python applications
  • Suspicious command execution patterns
  • YAML parsing errors with malicious payloads

Network Indicators:

  • Unusual outbound connections from Python processes
  • Command and control traffic patterns

SIEM Query:

process.name:python AND process.cmdline:*Popen* OR process.cmdline:*subprocess*

🔗 References

📤 Share & Export