Every CVE Search/ Get API key

CVE-2026-48170

scimPatch vulnerable to prototype pollution via unfiltered keys in patch

9.1 CriticalFix available

CVE-2026-48170 is a critical vulnerability (CVSS 9.1) in Thomaspoignant Scim-patch, published June 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.40%, the 34th percentile. Fixed in scim-patch 0.9.1.

scim-patch, a library to perform SCIM patch, prior to version 0.9.1 performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process. Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime. Version 0.9.1 contains a patch. A workaround is available. Calling Object.freeze(Object.prototype) (and the same on Array.prototype, Function.prototype) at process startup neutralizes this class of bug — assignment to a frozen prototype becomes a silent no-op in sloppy mode or a TypeError in strict mode. Node's --frozen-intrinsics flag does this for built-ins automatically.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
High
Availability
Low

Exploit likelihood

0.40%Up 0.2 points since Aug 8, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.1

scimPatch vulnerable to prototype pollution via unfiltered keys in patch

scim-patch, a library to perform SCIM patch, prior to version 0.9.1 performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process. Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime. Version 0.9.1 contains a patch. A workaround is available. Calling Object.freeze(Object.prototype) (and the same on Array.prototype, Function.prototype) at process startup neutralizes this class of bug — assignment to a frozen prototype becomes a silent no-op in sloppy mode or a TypeError in strict mode. Node's --frozen-intrinsics flag does this for built-ins automatically.

Record
CVE-2026-48170
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Weakness
CWE-1321
Updated
2026-11-02
EUVDEUVD-2026-54686 9.1

scim-patch, a library to perform SCIM patch, prior to version 0.9.1 performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process. Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime. Version 0.9.1 contains a patch. A workaround is available. Calling Object.freeze(Object.prototype) (and the same on Array.prototype, Function.prototype) at process startup neutralizes this class of bug — assignment to a frozen prototype becomes a silent no-op in sloppy mode or a TypeError in strict mode. Node's --frozen-intrinsics flag does this for built-ins automatically.

Record
EUVD-2026-54686
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-9m6g-wc8r-q59c 9.1

scimPatch vulnerable to prototype pollution via unfiltered keys in patch

Summary

scim-patch performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process.

Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime.

Impact

  • Class: Prototype pollution (CWE-1321)
  • Affected versions: <= 0.9.0 (current HEAD 871b1e2)
  • Attack vector: Network — sent as part of a normal SCIM PATCH /Users/:id request body.
  • Privileges required: Whatever the SCIM endpoint requires. For most integrations that's a provisioned IdP, which is "low" in CVSS terms (any authenticated provisioning client).
  • Scope: Changed — the bug is in a SCIM library but the side effect (Object.prototype mutation) leaks into the entire Node process.

Downstream consequences depend on what other code reads from plain objects. Realistic outcomes observed in similar bugs:

  • Privilege escalation if any auth/middleware code checks actor.isAdmin / req.user.admin / similar boolean flags against a plain object that expects the key to be absent.
  • Logic bypass / DoS if any code branches on obj.name, obj.type, obj.id etc. against plain objects (e.g. pg's prepared-statement naming check — a real incident at one consumer).
  • Persistence: lasts until the Node process restarts, so the blast radius is every request that container handles after the pollution.

Root cause

In src/scimPatch.ts:415-427, addOrReplaceObjectAttribute iterates the user-supplied patch.value with Object.entries and feeds each key to resolvePaths, which splits on .:

function addOrReplaceObjectAttribute(property: any, patch: ScimPatchAddReplaceOperation, multiValuedPathFilter?: boolean): any {
    if (typeof patch.value !== 'object') { ... }

    // src/scimPatch.ts:423-427
    for (const [key, value] of Object.entries(patch.value)) {
        assign(property, resolvePaths(key), value, patch.op);
    }
    return property;
}

assign then walks the resulting key path with no filtering on dangerous keys (src/scimPatch.ts:437-445):

function assign(obj: any, keyPath: Array<string>, value: any, op: string) {
    const lastKeyIndex = keyPath.length - 1;
    for (let i = 0; i < lastKeyIndex; ++i) {
        const key = keyPath[i];
        if (!(key in obj)) {
            obj[key] = {};
        }
        obj = obj[key];   // ← obj["__proto__"] === Object.prototype
    }
    // ... assigns into Object.prototype
}

For keyPath = ["__proto__", "polluted"]:

  • "__proto__" in obj is always true, so the fresh-object branch is skipped.
  • obj = obj["__proto__"] now points to Object.prototype.
  • The final write lands on Object.prototype.polluted.

The same shape works for constructor.prototype keys.

Proof of concept

Drop this in test/prototypePollution.test.ts and run npm run build && npx mocha lib/test/prototypePollution.test.js. Both tests pass against HEAD 871b1e2:

import { scimPatch } from '../src/scimPatch';
import { ScimUser } from './types/types.test';
import { expect } from 'chai';

describe('Prototype pollution via scim-patch', () => {
    let scimUser: ScimUser;

    beforeEach(() => {
        scimUser = JSON.parse(`{
          "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
          "id": "tea_4",
          "userName": "spiderman",
          "name": { "familyName": "Parker", "givenName": "Peter" },
          "active": true,
          "emails": [{ "value": "[email protected]", "primary": true }],
          "roles": [],
          "meta": { "resourceType": "User", "created": "x", "lastModified": "x", "location": "x" }
        }`);
    });

    afterEach(() => {
        delete…
Record
GHSA-9m6g-wc8r-q59c
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Weakness
CWE-1321
Updated
2026-11-02
NVD 9.1

scim-patch, a library to perform SCIM patch, prior to version 0.9.1 performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process. Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime. Version 0.9.1 contains a patch. A workaround is available. Calling Object.freeze(Object.prototype) (and the same on Array.prototype, Function.prototype) at process startup neutralizes this class of bug — assignment to a frozen prototype becomes a silent no-op in sloppy mode or a TypeError in strict mode. Node's --frozen-intrinsics flag does this for built-ins automatically.

Record
CVE-2026-48170
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Weakness
CWE-1321
Updated
2026-11-02
OSV 9.1

scimPatch vulnerable to prototype pollution via unfiltered keys in patch

scim-patch, a library to perform SCIM patch, prior to version 0.9.1 performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process. Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime. Version 0.9.1 contains a patch. A workaround is available. Calling Object.freeze(Object.prototype) (and the same on Array.prototype, Function.prototype) at process startup neutralizes this class of bug — assignment to a frozen prototype becomes a silent no-op in sloppy mode or a TypeError in strict mode. Node's --frozen-intrinsics flag does this for built-ins automatically.

Record
CVE-2026-48170
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Weakness
CWE-1321
Updated
2026-11-02
OSVGHSA-9m6g-wc8r-q59c 9.1

scimPatch vulnerable to prototype pollution via unfiltered keys in patch

Summary

scim-patch performs prototype pollution when applying a SCIM PATCH operation whose value object contains a key like "__proto__.someProp". After one such patch, Object.prototype.someProp is set process-wide, affecting every plain object in the Node process.

Any service that calls scimPatch() on attacker-controlled JSON (i.e. any SCIM endpoint accepting PATCH from an external IdP) is exploitable on a stock Node runtime.

Impact

  • Class: Prototype pollution (CWE-1321)
  • Affected versions: <= 0.9.0 (current HEAD 871b1e2)
  • Attack vector: Network — sent as part of a normal SCIM PATCH /Users/:id request body.
  • Privileges required: Whatever the SCIM endpoint requires. For most integrations that's a provisioned IdP, which is "low" in CVSS terms (any authenticated provisioning client).
  • Scope: Changed — the bug is in a SCIM library but the side effect (Object.prototype mutation) leaks into the entire Node process.

Downstream consequences depend on what other code reads from plain objects. Realistic outcomes observed in similar bugs:

  • Privilege escalation if any auth/middleware code checks actor.isAdmin / req.user.admin / similar boolean flags against a plain object that expects the key to be absent.
  • Logic bypass / DoS if any code branches on obj.name, obj.type, obj.id etc. against plain objects (e.g. pg's prepared-statement naming check — a real incident at one consumer).
  • Persistence: lasts until the Node process restarts, so the blast radius is every request that container handles after the pollution.

Root cause

In src/scimPatch.ts:415-427, addOrReplaceObjectAttribute iterates the user-supplied patch.value with Object.entries and feeds each key to resolvePaths, which splits on .:

function addOrReplaceObjectAttribute(property: any, patch: ScimPatchAddReplaceOperation, multiValuedPathFilter?: boolean): any {
    if (typeof patch.value !== 'object') { ... }

    // src/scimPatch.ts:423-427
    for (const [key, value] of Object.entries(patch.value)) {
        assign(property, resolvePaths(key), value, patch.op);
    }
    return property;
}

assign then walks the resulting key path with no filtering on dangerous keys (src/scimPatch.ts:437-445):

function assign(obj: any, keyPath: Array<string>, value: any, op: string) {
    const lastKeyIndex = keyPath.length - 1;
    for (let i = 0; i < lastKeyIndex; ++i) {
        const key = keyPath[i];
        if (!(key in obj)) {
            obj[key] = {};
        }
        obj = obj[key];   // ← obj["__proto__"] === Object.prototype
    }
    // ... assigns into Object.prototype
}

For keyPath = ["__proto__", "polluted"]:

  • "__proto__" in obj is always true, so the fresh-object branch is skipped.
  • obj = obj["__proto__"] now points to Object.prototype.
  • The final write lands on Object.prototype.polluted.

The same shape works for constructor.prototype keys.

Proof of concept

Drop this in test/prototypePollution.test.ts and run npm run build && npx mocha lib/test/prototypePollution.test.js. Both tests pass against HEAD 871b1e2:

import { scimPatch } from '../src/scimPatch';
import { ScimUser } from './types/types.test';
import { expect } from 'chai';

describe('Prototype pollution via scim-patch', () => {
    let scimUser: ScimUser;

    beforeEach(() => {
        scimUser = JSON.parse(`{
          "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
          "id": "tea_4",
          "userName": "spiderman",
          "name": { "familyName": "Parker", "givenName": "Peter" },
          "active": true,
          "emails": [{ "value": "[email protected]", "primary": true }],
          "roles": [],
          "meta": { "resourceType": "User", "created": "x", "lastModified": "x", "location": "x" }
        }`);
    });

    afterEach(() => {
        delete…
Record
GHSA-9m6g-wc8r-q59c
CVSS 3.1
9.1 CriticalCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:L
Weakness
CWE-1321
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
scim-patch
npm
through 0.9.0
0.9.1
scim-patch
npm
before 0.9.1
0.9.1

History

History
WhenChangedSources
2026-11-02createdCVE List, EUVD, GitHub Advisories, NVD, OSV

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open