Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"schema_version": "1.4.0",
"id": "GHSA-28xv-ph75-77wh",
"modified": "2026-07-14T19:40:05Z",
"modified": "2026-08-16T15:54:32Z",
"published": "2026-07-14T19:40:05Z",
"aliases": [
"CVE-2026-54335"
],
"summary": "Prototype pollution in @feathersjs/commons _.merge via JSON-parsed __proto__",
"details": "### Impact\n\nThe `_.merge(target, source)` utility exported by `@feathersjs/commons` recursively merges `source` into `target` by iterating `Object.keys(source)`. When `source` was produced by `JSON.parse` and contains a `__proto__` (or `constructor` / `prototype`) key, that key is returned as an own-enumerable property. The recursive merge then resolves `target['__proto__']` to `Object.prototype` and writes the attacker-supplied properties onto it, polluting the prototype for all plain objects in the process for the lifetime of the Node process.\n\n**Scope of real-world risk is limited.** No first-party Feathers package routes input — trusted or untrusted — through `commons._.merge`. The `@feathersjs/authentication` package, which does merge request-influenced data, uses `lodash/merge` (prototype-pollution-safe since 4.17.12), not this utility. Exploitation therefore requires a downstream plugin or application to pass JSON-parsed, attacker-controlled input directly through the exported `_.merge`.\n\n### Patches\n\nFixed in `@feathersjs/commons@5.0.45`. The fix skips `__proto__`, `constructor`, and `prototype` keys during iteration — the standard remediation used by lodash and others.\n\n### Workarounds\n\nAvoid passing JSON-parsed untrusted input through `commons._.merge`. Freezing `Object.prototype` or validating/sanitizing keys upstream also mitigates.\n\n### Credit\n\nReported responsibly by Andrew Ridings (@ridingsa).",
"details": "### Impact\n\nThe `_.merge(target, source)` utility exported by `@feathersjs/commons` recursively merges `source` into `target` by iterating `Object.keys(source)`. When `source` was produced by `JSON.parse` and contains a `__proto__` (or `constructor` / `prototype`) key, that key is returned as an own-enumerable property. The recursive merge then resolves `target['__proto__']` to `Object.prototype` and writes the attacker-supplied properties onto it, polluting the prototype for all plain objects in the process for the lifetime of the Node process.\n\n**Scope of real-world risk is limited.** No first-party Feathers package routes input \u2014 trusted or untrusted \u2014 through `commons._.merge`. The `@feathersjs/authentication` package, which does merge request-influenced data, uses `lodash/merge` (prototype-pollution-safe since 4.17.12), not this utility. Exploitation therefore requires a downstream plugin or application to pass JSON-parsed, attacker-controlled input directly through the exported `_.merge`.\n\n### Patches\n\n- **Feathers 5 (Dove):** fixed in `@feathersjs/commons@5.0.45` via https://github.com/feathersjs/feathers/pull/3690\n- **Feathers 4 (Crow):** fixed in `@feathersjs/commons@4.5.20` via https://github.com/feathersjs/feathers/pull/3695\n\nThe fix skips `__proto__`, `constructor`, and `prototype` keys during iteration \u2014 the standard remediation used by lodash and others.\n\nRecommended install targets:\n- Crow / Feathers 4: `@feathersjs/commons@4.5.21` or later (4.5.20 contains this security fix; 4.5.21 is the preferred Crow monorepo release)\n- Dove / Feathers 5: `@feathersjs/commons@5.0.45` or later\n\n### Workarounds\n\nAvoid passing JSON-parsed untrusted input through `commons._.merge`. Freezing `Object.prototype` or validating/sanitizing keys upstream also mitigates.\n\n### Credit\n\nReported responsibly by Andrew Ridings (@ridingsa).\n",
"severity": [
{
"type": "CVSS_V3",
Expand All @@ -25,7 +25,29 @@
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
"introduced": "4.0.0"
},
{
"fixed": "4.5.20"
}
]
}
],
"database_specific": {
"last_known_affected_version_range": "<= 4.5.19"
}
},
{
"package": {
"ecosystem": "npm",
"name": "@feathersjs/commons"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "5.0.0"
},
{
"fixed": "5.0.45"
Expand All @@ -51,13 +73,29 @@
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/commit/28b3c03c63bdbff53115fdaa46c56980e7942acc"
},
{
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/pull/3695"
},
{
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/commit/88794cc432ce09e5559780545faa8134359abcce"
},
{
"type": "PACKAGE",
"url": "https://github.com/feathersjs/feathers"
},
{
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/releases/tag/v5.0.45"
},
{
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/releases/tag/v4.5.20"
},
{
"type": "WEB",
"url": "https://github.com/feathersjs/feathers/releases/tag/v4.5.21"
}
],
"database_specific": {
Expand All @@ -69,4 +107,4 @@
"github_reviewed_at": "2026-07-14T19:40:05Z",
"nvd_published_at": null
}
}
}