VYPR
Moderate severityNVD Advisory· Published Sep 24, 2025· Updated Sep 25, 2025

CVE-2025-57324

CVE-2025-57324

Description

parse is a package designed to parse JavaScript SDK. A Prototype Pollution vulnerability in the SingleInstanceStateController.initializeState function of parse version 5.3.0 and before allows attackers to inject properties on Object.prototype via supplying a crafted payload, causing denial of service (DoS) as the minimum consequence.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Prototype Pollution in Parse JavaScript SDK <=5.3.0 via SingleInstanceStateController.initializeState allows attackers to cause denial of service by injecting properties on Object.prototype.

Vulnerability

Overview

CVE-2025-57324 is a Prototype Pollution vulnerability in the Parse JavaScript SDK version 5.3.0 and earlier. The flaw resides in the SingleInstanceStateController.initializeState function, which improperly handles the className parameter. By providing a crafted payload with a className value set to __proto__, constructor, or prototype, an attacker can inject arbitrary properties onto Object.prototype [1][4].

Exploitation

Conditions

An attacker able to supply input to the Parse SDK's state initialization, such as via a malicious object or user-controlled data, can exploit this vulnerability. No special authentication or network access is required beyond typical usage of the SDK. The PoC demonstrates that simply calling initializeState with a payload containing className: '__proto__' suffices to pollute the global prototype [4].

Impact

The primary impact is denial of service (DoS), as polluted prototypes can cause unexpected behavior, crashes, or infinite loops in applications relying on the SDK. Additionally, prototype pollution can lead to security control bypasses or further exploitation depending on the application context [1][4].

Mitigation

The vulnerability has been fixed in commit 9e7c1ba [3]. Users are strongly advised to upgrade to a patched version. No workarounds are documented, but ensuring that user-supplied data is sanitized before reaching the vulnerable function may reduce risk.

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
parsenpm
< 7.0.0-alpha.17.0.0-alpha.1

Affected products

1
  • parse/parsedescription

Patches

1
9e7c1bad472b

fix: Prototype Pollution vulnerability in `SingleInstanceStateController`; fixes security vulnerability [GHSA-9g8m-v378-pcg3](https://github.com/advisories/GHSA-9g8m-v378-pcg3) (#2745)

https://github.com/parse-community/Parse-SDK-JSAntoine CormoulsOct 14, 2025via ghsa
3 files changed · +124 15
  • src/SingleInstanceStateController.ts+30 10 modified
    @@ -1,10 +1,17 @@
    -import * as ObjectStateMutations from './ObjectStateMutations';
    +import * as ObjectStateMutations from "./ObjectStateMutations";
     
    -import type { Op } from './ParseOp';
    -import type ParseObject from './ParseObject';
    -import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations';
    +import type { Op } from "./ParseOp";
    +import type ParseObject from "./ParseObject";
    +import type {
    +  AttributeMap,
    +  ObjectCache,
    +  OpsMap,
    +  State,
    +} from "./ObjectStateMutations";
     
    -let objectState: Record<string, Record<string, State>> = {};
    +// Use Object.create(null) to create an object without prototype chain
    +// This prevents prototype pollution attacks
    +let objectState: Record<string, Record<string, State>> = Object.create(null);
     
     export function getState(obj: ParseObject): State | null {
       const classData = objectState[obj.className];
    @@ -20,7 +27,8 @@ export function initializeState(obj: ParseObject, initial?: State): State {
         return state;
       }
       if (!objectState[obj.className]) {
    -    objectState[obj.className] = {};
    +    // Use Object.create(null) for nested objects too
    +    objectState[obj.className] = Object.create(null);
       }
       if (!initial) {
         initial = ObjectStateMutations.defaultState();
    @@ -90,7 +98,12 @@ export function getObjectCache(obj: ParseObject): ObjectCache {
     export function estimateAttribute(obj: ParseObject, attr: string): any {
       const serverData = getServerData(obj);
       const pendingOps = getPendingOps(obj);
    -  return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj, attr);
    +  return ObjectStateMutations.estimateAttribute(
    +    serverData,
    +    pendingOps,
    +    obj,
    +    attr
    +  );
     }
     
     export function estimateAttributes(obj: ParseObject): AttributeMap {
    @@ -101,16 +114,23 @@ export function estimateAttributes(obj: ParseObject): AttributeMap {
     
     export function commitServerChanges(obj: ParseObject, changes: AttributeMap) {
       const state = initializeState(obj);
    -  ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes);
    +  ObjectStateMutations.commitServerChanges(
    +    state.serverData,
    +    state.objectCache,
    +    changes
    +  );
     }
     
    -export function enqueueTask(obj: ParseObject, task: () => Promise<any>): Promise<void> {
    +export function enqueueTask(
    +  obj: ParseObject,
    +  task: () => Promise<any>
    +): Promise<void> {
       const state = initializeState(obj);
       return state.tasks.enqueue(task);
     }
     
     export function clearAllState() {
    -  objectState = {};
    +  objectState = Object.create(null);
     }
     
     export function duplicateState(source: { id: string }, dest: { id: string }) {
    
  • src/__tests__/SingleInstanceStateController-test.js+91 2 modified
    @@ -10,8 +10,8 @@ jest.dontMock('../SingleInstanceStateController');
     jest.dontMock('../TaskQueue');
     jest.dontMock('./test_helpers/flushPromises');
     
    -const mockObject = function () {};
    -mockObject.registerSubclass = function () {};
    +const mockObject = function () { };
    +mockObject.registerSubclass = function () { };
     jest.setMock('../ParseObject', {
       __esModule: true,
       default: mockObject,
    @@ -698,4 +698,93 @@ describe('SingleInstanceStateController', () => {
           existed: false,
         });
       });
    +
    +  describe('Prototype Pollution Protection (CVE-2025-57324)', () => {
    +    beforeEach(() => {
    +      SingleInstanceStateController.clearAllState();
    +    });
    +
    +    it('prevents prototype pollution via __proto__ as className', () => {
    +      const testObj = { className: '__proto__', id: 'pollutedProperty' };
    +
    +      // Should not throw error (silent prevention via Object.create(null))
    +      SingleInstanceStateController.initializeState(testObj, {});
    +
    +      // Verify no pollution occurred on actual Object.prototype
    +      expect({}.pollutedProperty).toBe(undefined);
    +      expect(Object.prototype.pollutedProperty).toBe(undefined);
    +    });
    +
    +    it('prevents prototype pollution via constructor as className', () => {
    +      const testObj = { className: 'constructor', id: 'testId' };
    +
    +      // Should not throw error (silent prevention)
    +      SingleInstanceStateController.initializeState(testObj, {});
    +
    +      // Verify no pollution occurred
    +      const freshObj = {};
    +      expect(freshObj.testId).toBe(undefined);
    +    });
    +
    +    it('prevents prototype pollution via prototype as className', () => {
    +      const testObj = { className: 'prototype', id: 'testId' };
    +
    +      // Should not throw error (silent prevention)
    +      SingleInstanceStateController.initializeState(testObj, {});
    +
    +      // Verify no pollution occurred
    +      const freshObj = {};
    +      expect(freshObj.testId).toBe(undefined);
    +    });
    +
    +    it('prevents prototype pollution via __proto__ as id', () => {
    +      const testObj = { className: 'TestClass', id: '__proto__' };
    +
    +      // Should not throw error (silent prevention)
    +      SingleInstanceStateController.initializeState(testObj, {});
    +
    +      // Verify no pollution occurred
    +      expect({}.TestClass).toBe(undefined);
    +    });
    +
    +    it('can store and retrieve data even with dangerous property names', () => {
    +      const testObj1 = { className: '__proto__', id: 'pollutedProperty' };
    +      const testObj2 = { className: 'constructor', id: 'testId' };
    +
    +      // Should work normally without polluting
    +      SingleInstanceStateController.setServerData(testObj1, { value: 'test1' });
    +      SingleInstanceStateController.setServerData(testObj2, { value: 'test2' });
    +
    +      // Should be able to retrieve the data
    +      const state1 = SingleInstanceStateController.getState(testObj1);
    +      const state2 = SingleInstanceStateController.getState(testObj2);
    +
    +      expect(state1.serverData).toEqual({ value: 'test1' });
    +      expect(state2.serverData).toEqual({ value: 'test2' });
    +
    +      // But no pollution should occur
    +      expect({}.pollutedProperty).toBe(undefined);
    +      expect({}.testId).toBe(undefined);
    +    });
    +
    +    it('allows normal className and id values', () => {
    +      const testObj = { className: 'NormalClass', id: 'normalId123' };
    +
    +      SingleInstanceStateController.setServerData(testObj, { counter: 12 });
    +
    +      const state = SingleInstanceStateController.getState(testObj);
    +      expect(state).toBeTruthy();
    +      expect(state.serverData).toEqual({ counter: 12 });
    +    });
    +
    +    it('prevents pollution when removing dangerous property names', () => {
    +      const testObj = { className: '__proto__', id: 'dangerousId' };
    +
    +      SingleInstanceStateController.setServerData(testObj, { data: 'test' });
    +      SingleInstanceStateController.removeState(testObj);
    +
    +      // Verify no pollution occurred
    +      expect({}.dangerousId).toBe(undefined);
    +    });
    +  });
     });
    
  • types/SingleInstanceStateController.d.ts+3 3 modified
    @@ -1,6 +1,6 @@
    -import type { Op } from './ParseOp';
    -import type ParseObject from './ParseObject';
    -import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations';
    +import type { Op } from "./ParseOp";
    +import type ParseObject from "./ParseObject";
    +import type { AttributeMap, ObjectCache, OpsMap, State } from "./ObjectStateMutations";
     export declare function getState(obj: ParseObject): State | null;
     export declare function initializeState(obj: ParseObject, initial?: State): State;
     export declare function removeState(obj: ParseObject): State | null;
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.