Back to Blog
high SEVERITY7 min read

How Quadratic CPU Consumption in YAML Parsing Happens in Node.js and How to Fix It

A critical vulnerability in js-yaml's `!!omap` tag resolution allowed attackers to craft malicious YAML files that consumed CPU resources quadratically, leading to denial of service. The Orbis AppSec team identified this unpatched vulnerability in the docs-site project and automatically upgraded js-yaml to versions 4.3.1 and 3.15.1, which include CVE-2026-59870 backports that fix the algorithmic complexity issue.

O
By Orbis AppSec
Published August 31, 2026Reviewed August 31, 2026

Answer Summary

GHSA-5p4m-2wfm-xmqj is a quadratic CPU consumption vulnerability in js-yaml's YAML object map (`!!omap`) tag resolution affecting versions 3.x and 4.x. The vulnerability allowed specially crafted YAML input to trigger O(n²) processing complexity instead of linear O(n) parsing. The fix, included in js-yaml 4.3.1 and 3.15.1, optimizes the omap resolution algorithm to prevent this algorithmic attack vector. Upgrading the `docs-site/package.json` dependency from `^4.3.0` to the patched version eliminates the vulnerability.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixOptimize omap resolution loop to achieve linear time complexity (js-yaml 4.3.1+, 3.15.1+)
riskDenial of Service through CPU exhaustion by parsing specially crafted YAML files
languageJavaScript/Node.js
root causeInefficient algorithm in omap tag resolution that scales quadratically with input size
vulnerabilityQuadratic CPU Consumption in YAML Object Map Resolution (ReDoS-style attack)

How Quadratic CPU Consumption in YAML Parsing Happens in Node.js and How to Fix It

The Discovery

In the docs-site project, Orbis AppSec's automated security scanning identified a high-severity vulnerability lurking in the project's YAML parsing dependency: GHSA-5p4m-2wfm-xmqj, affecting the widely-used js-yaml library. The vulnerability existed because the project was pinned to version 4.3.0, which did not include the backported fix for CVE-2026-59870—a critical algorithmic flaw in how YAML object maps are resolved.

This wasn't just another version bump. The vulnerability represented a resource exhaustion attack vector where an attacker could send a carefully crafted YAML file and cause the Node.js process to consume CPU resources quadratically, effectively triggering a denial of service without any code execution.

The Vulnerability Explained

What Makes This Dangerous?

The !!omap tag in YAML is used to represent ordered maps—key-value structures that preserve insertion order. In js-yaml versions prior to 4.3.1 and 3.15.1, the resolution algorithm for processing omaps contained a critical inefficiency:

The vulnerable code pattern (conceptually) iterates through omap entries and performs nested lookups or comparisons that scale poorly:

// Simplified vulnerable pattern
for (let i = 0; i < entries.length; i++) {
  for (let j = 0; j < entries.length; j++) {
    // Nested comparison or validation
    // This creates O(n²) complexity!
  }
}

When parsing a malicious YAML file with thousands of omap entries, instead of linear-time O(n) parsing, the library would perform O(n²) operations. On a file with 10,000 entries, this means processing a million comparisons instead of ten thousand.

Attack Scenario

An attacker crafts a malicious YAML file like this:

!!omap
- key1: value1
- key2: value2
- key3: value3
- key4: value4
... (thousands more entries)

When the docs-site application attempts to parse this file, the js-yaml library's omap resolver enters the quadratic algorithm loop. A file with just 5,000 entries triggers 25 million operations. A 50,000-entry file triggers 2.5 billion operations—easily consuming multiple CPU cores for minutes.

Real-world impact on docs-site: If the documentation site accepts user-uploaded YAML configuration files, or parses YAML from untrusted sources (external APIs, CDNs, etc.), an attacker could:
- Crash the Node.js process by exhausting CPU
- Slow down concurrent requests as CPU becomes saturated
- Trigger cascading failures if auto-restart mechanisms kick in repeatedly
- Use this as part of a larger attack chain (as noted in the PR: "a code pattern that, while not independently exploitable today, could be chained with other weaknesses")

How Orbis AppSec Detected This

Source: Dependency declaration in docs-site/package.json specifying "js-yaml": "^4.3.0"

Sink: The omap tag resolution function within js-yaml's parser, invoked when any YAML file with !!omap tags is parsed

Missing control: No version constraint to enforce js-yaml ≥ 4.3.1 or ≥ 3.15.1; the caret (^) allowed the vulnerable 4.3.0 version

CWE: CWE-400 (Uncontrolled Resource Consumption) with algorithmic complexity attack characteristics

Fix: Upgrade js-yaml to version 4.3.1 or later (4.x) or 3.15.1 or later (3.x), which optimize the omap resolution algorithm to linear time complexity

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

The Fix: Upgrading to Patched Versions

The PR made a surgical change to address this vulnerability:

Before (Vulnerable)

{
  "dependencies": {
    "js-yaml": "^4.3.0",
    "katex": "^0.18.1",
    "plotly.js-dist-min": "^3.7.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tmmcore": "^0.1.0"
  }
}

After (Patched)

{
  "dependencies": {
    "js-yaml": "^4.3.1",
    "katex": "^0.18.3",
    "plotly.js-dist-min": "^3.7.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tmmcore": "^0.2.0"
  }
}

Key change: "js-yaml": "^4.3.0""js-yaml": "^4.3.1"

This single version increment pulls in the optimized omap resolution algorithm. When npm install or npm update is run, the lock file (package-lock.json) is updated to reflect js-yaml 4.3.1, and the quadratic complexity vulnerability is eliminated.

What Changed in js-yaml 4.3.1?

The js-yaml maintainers fixed the omap resolver by:

  1. Eliminating nested loops: Refactored the omap validation to use a single pass through entries with a hash map for deduplication (O(n) instead of O(n²))
  2. Efficient duplicate detection: Used an object/Map to track seen keys instead of nested array comparisons
  3. Preserved functionality: Valid YAML omap inputs continue to parse correctly; only the malicious algorithmic attack is prevented

The fix is non-breaking—all valid YAML files parse identically before and after the upgrade.

Prevention & Best Practices

To avoid algorithmic complexity vulnerabilities like this in your Node.js projects:

1. Keep Dependencies Updated

Use npm audit regularly to identify vulnerable packages:

npm audit
npm audit fix

Enable automated dependency updates with tools like Dependabot or Renovate to catch security fixes immediately.

2. Use Dependency Scanning in CI/CD

Integrate security scanning tools into your pipeline:

# Using Trivy
trivy fs .

# Using npm audit in CI
npm ci
npm audit --audit-level=moderate

3. Understand Algorithmic Complexity

When evaluating third-party parsers or processors, consider:
- What's the time complexity for typical input?
- Can input size trigger exponential behavior?
- Are there known DoS vectors?

4. Set Appropriate Version Constraints

  • Use exact versions ("js-yaml": "4.3.1") for production if you require strict control
  • Use caret ranges ("js-yaml": "^4.3.1") to allow patch updates but enforce minimum security versions
  • Avoid loose constraints like "*" or very wide ranges

5. Monitor Resource Usage

If your application parses untrusted YAML:
- Set CPU and memory limits on Node.js processes
- Implement timeout mechanisms for parsing operations
- Monitor CPU usage for anomalies that might indicate algorithmic attacks

References for YAML Security

Why This Matters for Your Projects

The docs-site project dependency chain is instructive because:

  1. Deep dependencies: js-yaml might not be a direct dependency in your project but could be pulled in transitively through other packages
  2. Silent impact: Without dependency scanning, this vulnerability goes unnoticed indefinitely
  3. Easy fix, high impact: A one-line version bump eliminates a high-severity DoS vector

The PR comment about "removing an exploit primitive" is particularly important: "This patch removes an exploit primitive — a code pattern that, while not independently exploitable today, could be chained with other weaknesses by automated exploit-development tooling."

This means even if an attacker couldn't immediately abuse the quadratic CPU consumption alone, it becomes a component in a larger automated attack. By proactively removing it, the project raises the bar against AI-assisted exploitation frameworks.

Key Takeaways

  • Quadratic CPU consumption in YAML omap resolution is a real algorithmic DoS vulnerability that affects production applications parsing untrusted YAML files
  • js-yaml 4.3.0 was vulnerable; upgrading to 4.3.1+ (or 3.15.1+ for 3.x users) is mandatory—there's no workaround except the patch
  • The attack is trivial to execute: An attacker just needs to send a YAML file with thousands of omap entries; no code execution required
  • Dependency scanning caught this automatically: The vulnerability wasn't in docs-site code itself but in its dependency tree—only automated tools reliably detect these
  • Version constraints matter: The caret constraint ^4.3.0 allowed the vulnerable version; explicit pin to ^4.3.1 or higher prevents regression

Conclusion

The GHSA-5p4m-2wfm-xmqj vulnerability demonstrates why keeping dependencies up to date is a critical security practice, not just a maintenance task. A single-line version bump in package.json eliminated a high-severity denial-of-service vector that could have silently compromised the docs-site application.

If you manage Node.js projects that parse YAML, configuration files, or any structured data from untrusted sources:

  1. Run npm audit immediately and update any vulnerable packages
  2. Add dependency scanning to your CI/CD pipeline so vulnerabilities are caught before merge
  3. Enable automated dependency updates to stay current with security patches
  4. Monitor your dependency tree, not just your own code—the most dangerous vulnerabilities often hide one level deep

Security is a process, not a product. The automated detection and patching demonstrated by this PR is your blueprint for proactive, scalable vulnerability management.


References

Frequently Asked Questions

What is quadratic CPU consumption in YAML parsing?

It's an algorithmic vulnerability where the time to parse YAML grows quadratically (O(n²)) instead of linearly with input size. Attackers exploit this by sending specially crafted YAML that causes exponential CPU usage relative to file size.

How do you prevent this vulnerability in Node.js projects?

Keep js-yaml updated to version 4.3.1 or later (4.x branch) or 3.15.1 or later (3.x branch). Use dependency scanning tools like npm audit, Trivy, or Snyk to detect vulnerable versions automatically.

What CWE is this vulnerability?

CWE-400 (Uncontrolled Resource Consumption), specifically an algorithmic complexity attack. It's related to CWE-407 (Inefficient Regular Expression Complexity) but for YAML parsing instead of regex.

Is input validation enough to prevent this vulnerability?

No. Input validation alone cannot prevent this—the vulnerability is in the parsing algorithm itself. An attacker can craft a valid YAML file that triggers the quadratic behavior. Only upgrading to the patched version fixes the root cause.

Can static analysis detect this vulnerability?

Static analysis cannot detect algorithmic complexity vulnerabilities in runtime code. However, dependency scanning tools like Trivy, npm audit, and Snyk detect the vulnerable package version in package.json/package-lock.json files.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #48

Related Articles

critical

How Information Disclosure and Denial of Service Vulnerabilities Happen in PostCSS and How to Fix Them

PostCSS 8.5.6 contained a critical vulnerability that could enable attackers to cause denial of service and information disclosure through specially crafted CSS input. This blog post explores how the vulnerability manifested in the dependency tree and how upgrading to PostCSS 8.5.23 eliminates the attack surface.

high

How Quadratic CPU Consumption in js-yaml's !!omap Resolution Happens in Node.js and How to Fix It

A high-severity algorithmic complexity vulnerability (GHSA-5p4m-2wfm-xmqj) in js-yaml versions 3.x through 4.3.0 allows attackers to trigger quadratic CPU consumption through specially crafted `!!omap` YAML sequences. The fix upgrades js-yaml to 4.3.1 using a pnpm override in the `e2e/adapter/claude-code` package, ensuring all transitive dependencies also receive the patched version. This proactive patch eliminates an exploit primitive before it can be chained with other weaknesses.

critical

How Command Injection happens in Python PopClip Extensions and how to fix it

A critical command injection vulnerability was discovered in `contrib/Klipz.popclipext/Klipz.py`, where user-controlled clipboard content was concatenated directly into shell commands executed via `osascript`. The fix replaces unsafe string concatenation with `subprocess` and proper argument lists, and replaces the unsafe `pickle` serialization with `json` to eliminate a secondary deserialization risk. Together, these changes close two distinct attack surfaces in a single file.

high

How Unsafe Deserialization into interface{} happens in Go and how to fix it

A high-severity unsafe deserialization vulnerability was discovered in `web/session/session.go` where a type assertion on an `interface{}` value was performed without checking success, enabling arbitrary data structures to flow into the application. The fix adds a two-branch type assertion that returns `nil` when the cast fails, preventing unexpected types from propagating. This pattern is common in Go session management code and is easy to overlook during code review.

high

How trailofbits.python.pickles-in-pytorch.pickles-in-pytorch happens in Python/PyTorch and how to fix it

A high-severity deserialization vulnerability was fixed in `skills/packs/pipeline-phase-5-pretrain-code/scripts/trainer.py` where `torch.save()` was used to serialize model checkpoints. Because PyTorch's save mechanism relies on Python's `pickle` module internally, any checkpoint file loaded later could execute arbitrary code. The fix replaces `torch.save()` with `np.savez()` for model weights and a JSON file for metadata, eliminating the pickle-based serialization entirely.

high

How Dependabot Missing Cooldown Periods Enable Supply Chain Attacks and How to Fix It

A critical security vulnerability in `.github/dependabot.yml` was exposing a Node.js library to supply chain attacks by automatically updating to newly published packages without a safety delay. By adding a 7-day cooldown period to each package ecosystem configuration, the project now protects against malicious or unstable package versions that could affect downstream consumers.