Introduction
The apps/dsa-desktop application ships as an Electron desktop app that relies on electron-builder and electron-updater to manage build configuration and auto-update metadata — both of which parse YAML files under the hood using the js-yaml package. A scan by Orbis AppSec flagged apps/dsa-desktop/package-lock.json for pulling in js-yaml@4.1.1, a version affected by GHSA-5p4m-2wfm-xmqj, a high-severity quadratic CPU consumption issue in how js-yaml resolves the !!omap YAML type.
This isn't a bug in application code — it's a transitive dependency risk. js-yaml is one of the most widely used YAML parsers in the JavaScript ecosystem, and it's pulled in indirectly by build tooling, CI configuration loaders, and update mechanisms like electron-updater. If any part of the build or update pipeline parses YAML that isn't fully trusted (for example, YAML fetched from a remote update feed, a CI artifact, or a config file supplied by a third party), an attacker-crafted document could trigger pathological CPU usage.
The Vulnerability Explained
The root cause lives inside js-yaml's type resolution logic for the !!omap tag — YAML's "ordered map" type. In the affected versions (including 4.1.1, which was pinned in this repo before the fix), the resolver used an algorithm whose runtime scales quadratically, O(n²), with the number of entries in the map being resolved.
Before the fix, package-lock.json looked like this:
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
}
}
This version was resolved and installed without any override, meaning any code path in electron-builder/electron-updater that calls into js-yaml to parse configuration or update metadata would run with the vulnerable resolver.
How this could be exploited
Picture an attacker who can influence YAML content consumed anywhere along the build or auto-update pipeline for apps/dsa-desktop — for instance, a malicious or compromised electron-builder config, a spoofed update feed response, or a crafted CI artifact that gets parsed as YAML. If that YAML contains a deeply structured !!omap block, the parser's quadratic-time resolution means that even a moderate document (say, a few thousand ordered-map entries) can force js-yaml — and by extension, the Node.js process running the build or the desktop app's update checker — to burn CPU cycles disproportionately to the input size.
In a build server context, this could stall CI pipelines. In a desktop-app update context, it could hang the update-check process, degrading the user experience or creating a denial-of-service condition against the app's own tooling. The Orbis AppSec assessment notes this was "present in dependency tree, not confirmed reachable" — meaning it wasn't proven to be actively exploitable in this codebase's current call paths, but the exploit primitive existed and could be chained by automated tooling if a reachable code path is introduced later.
The Fix
The fix is a targeted dependency upgrade, touching exactly two files: apps/dsa-desktop/package.json and apps/dsa-desktop/package-lock.json.
1. Upgrading the resolved version in package-lock.json:
"node_modules/js-yaml": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
+ "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
}
This locks the resolved package to js-yaml@4.3.1, which contains the backported fix for the !!omap quadratic-time resolution — restoring linear-time behavior for ordered map parsing.
2. Pinning the version with an npm overrides entry in package.json:
"overrides": {
- "builder-util-runtime": "9.7.0"
+ "builder-util-runtime": "9.7.0",
+ "js-yaml": "4.3.1"
}
This second change is just as important as the version bump itself. Because js-yaml is a transitive dependency — pulled in indirectly through electron-builder and electron-updater — simply bumping the lockfile entry isn't enough to guarantee future installs stay safe. Any nested dependency could still declare a semver range that resolves back down to a vulnerable 4.x release. Adding "js-yaml": "4.3.1" to the overrides block forces npm to resolve every occurrence of js-yaml in the dependency tree to the patched version, regardless of what version range upstream packages request.
Prevention & Best Practices
- Use npm
overrides(or Yarnresolutions) for security-critical transitive dependencies. This repo already had a precedent —builder-util-runtimewas pinned the same way — and extending that pattern tojs-yamlcloses the gap for a package with a known quadratic-complexity flaw. - Run dependency scanners like Trivy,
npm audit, or Snyk in CI so advisories like GHSA-5p4m-2wfm-xmqj are caught automatically as soon as they're published, rather than discovered manually. - Treat any YAML parsing of external input as untrusted, even when it's "just" build configuration or update metadata — auto-update pipelines are a high-value target precisely because they run with elevated trust.
- Prefer
js-yaml'ssafeLoad/loadwith schema restrictions where possible, and avoid loading YAML that allows arbitrary custom tags unless strictly necessary. - Track algorithmic-complexity advisories, not just RCE/injection CVEs. DoS-class issues like CWE-407 are easy to overlook but can be just as disruptive to CI/CD and production services.
Key Takeaways
js-yaml@4.1.1, previously locked inapps/dsa-desktop/package-lock.json, contained a quadratic-time algorithm in its!!omaptype resolver (GHSA-5p4m-2wfm-xmqj / CVE-2026-59870).- The fix upgrades to
js-yaml@4.3.1(with3.15.1for consumers still on the 3.x line) and hard-pins the version viapackage.json'soverridesfield. js-yamlwas present as a transitive dependency ofelectron-builder/electron-updater, illustrating how build tooling can silently drag vulnerable parsers into a desktop application's dependency tree.- Even when a flaw is "not confirmed reachable" in current code paths, removing the exploit primitive proactively — as was done here — reduces the attack surface available to automated exploit chaining tools.
- Pinning transitive dependencies with
overrides/resolutionsis a reusable pattern already established in this codebase (builder-util-runtime) and should be applied consistently to other security-sensitive transitive packages.
How Orbis AppSec Detected This
- Source: Untrusted YAML documents processed by
electron-builder/electron-updatertooling (e.g., build configuration or update-feed metadata) that reachjs-yaml's type resolution logic. - Sink:
js-yaml's internal!!omaptype resolver, invoked wheneverjs-yaml.load()/safeLoad()parses a YAML document containing an ordered-map tag, bundled transitively inapps/dsa-desktop/package-lock.json. - Missing control: No pinned/patched version of
js-yamlwas enforced across the dependency tree — the vulnerable4.1.1release was resolved with nooverridesentry to force an upgrade. - CWE: CWE-407 (Inefficient Algorithmic Complexity), commonly grouped under Denial-of-Service issues.
- Fix: Upgraded
js-yamlto4.3.1(3.15.1 on the legacy line) and added anoverridesentry inpackage.jsonto force the patched version across all transitive resolutions.
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.
Conclusion
This vulnerability is a good reminder that security risk doesn't only come from code you write — it also comes from the dependency graph beneath your build and update tooling. A quadratic-time flaw in js-yaml's !!omap resolution sat quietly in apps/dsa-desktop's lockfile, reachable only through the transitive chain from electron-builder/electron-updater. The fix was small but precise: bump js-yaml to the patched 4.3.1 release and enforce that version tree-wide with an npm overrides entry, following the same pattern already used for builder-util-runtime. Treat dependency advisories — even DoS-class ones — with the same urgency as injection or RCE bugs, and use version-pinning mechanisms to make sure a patched version actually sticks across your entire dependency tree.