VYPR
Medium severity5.4NVD Advisory· Published Mar 31, 2026· Updated Apr 2, 2026

CVE-2026-34574

CVE-2026-34574

Description

Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Prior to versions 8.6.69 and 9.7.0-alpha.14, an authenticated user can bypass the immutability guard on session fields (expiresAt, createdWith) by sending a null value in a PUT request to the session update endpoint. This allows nullifying the session expiry, making the session valid indefinitely and bypassing configured session length policies. This issue has been patched in versions 8.6.69 and 9.7.0-alpha.14.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
parse-servernpm
>= 9.0.0, < 9.7.0-alpha.149.7.0-alpha.14
parse-servernpm
< 8.6.698.6.69

Affected products

14
  • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha11:*:*:*:node.js:*:*+ 13 more
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha11:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha12:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha13:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha2:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha3:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha4:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha5:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha6:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha7:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha8:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha9:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:*:*:*:*:*:node.js:*:*range: <8.6.69
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha1:*:*:*:node.js:*:*
    • cpe:2.3:a:parseplatform:parse-server:9.7.0:alpha10:*:*:*:node.js:*:*

Patches

2
ebccd7fe2708

fix: Session field immutability bypass via falsy-value guard ([GHSA-f6j3-w9v3-cq22](https://github.com/parse-community/parse-server/security/advisories/GHSA-f6j3-w9v3-cq22)) (#10348)

2 files changed · +156 4
  • spec/ParseSession.spec.js+152 0 modified
    @@ -393,4 +393,156 @@ describe('Parse.Session', () => {
         });
         expect(verifyRes.data.expiresAt.iso).toBe(farFuture);
       });
    +
    +  it('should reject null expiresAt when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull1', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +    const originalExpiresAt = sessionRes.data.expiresAt;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        expiresAt: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +
    +    const verifyRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    expect(verifyRes.data.expiresAt).toEqual(originalExpiresAt);
    +  });
    +
    +  it('should reject null createdWith when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull2', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +    const originalCreatedWith = sessionRes.data.createdWith;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        createdWith: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +
    +    const verifyRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    expect(verifyRes.data.createdWith).toEqual(originalCreatedWith);
    +  });
    +
    +  it('should reject null installationId when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull3', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        installationId: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +  });
    +
    +  it('should reject null sessionToken when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull4', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        sessionToken: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +  });
     });
    
  • src/RestWrite.js+4 4 modified
    @@ -1174,13 +1174,13 @@ RestWrite.prototype.handleSession = function () {
       if (this.query) {
         if (this.data.user && !this.auth.isMaster && this.data.user.objectId != this.auth.user.id) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
    -    } else if (this.data.installationId) {
    +    } else if ('installationId' in this.data) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
    -    } else if (this.data.sessionToken) {
    +    } else if ('sessionToken' in this.data) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
    -    } else if (this.data.expiresAt && !this.auth.isMaster && !this.auth.isMaintenance) {
    +    } else if ('expiresAt' in this.data && !this.auth.isMaster && !this.auth.isMaintenance) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
    -    } else if (this.data.createdWith && !this.auth.isMaster && !this.auth.isMaintenance) {
    +    } else if ('createdWith' in this.data && !this.auth.isMaster && !this.auth.isMaintenance) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
         }
         if (!this.auth.isMaster) {
    
90802969fc71

fix: Session field immutability bypass via falsy-value guard ([GHSA-f6j3-w9v3-cq22](https://github.com/parse-community/parse-server/security/advisories/GHSA-f6j3-w9v3-cq22)) (#10347)

2 files changed · +156 4
  • spec/ParseSession.spec.js+152 0 modified
    @@ -394,6 +394,158 @@ describe('Parse.Session', () => {
         expect(verifyRes.data.expiresAt.iso).toBe(farFuture);
       });
     
    +  it('should reject null expiresAt when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull1', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +    const originalExpiresAt = sessionRes.data.expiresAt;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        expiresAt: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +
    +    const verifyRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    expect(verifyRes.data.expiresAt).toEqual(originalExpiresAt);
    +  });
    +
    +  it('should reject null createdWith when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull2', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +    const originalCreatedWith = sessionRes.data.createdWith;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        createdWith: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +
    +    const verifyRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    expect(verifyRes.data.createdWith).toEqual(originalCreatedWith);
    +  });
    +
    +  it('should reject null installationId when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull3', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        installationId: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +  });
    +
    +  it('should reject null sessionToken when updating a session via PUT', async () => {
    +    const user = await Parse.User.signUp('sessionupdatenull4', 'password');
    +    const sessionToken = user.getSessionToken();
    +
    +    const sessionRes = await request({
    +      method: 'GET',
    +      url: 'http://localhost:8378/1/sessions/me',
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +      },
    +    });
    +    const sessionId = sessionRes.data.objectId;
    +
    +    const updateRes = await request({
    +      method: 'PUT',
    +      url: `http://localhost:8378/1/sessions/${sessionId}`,
    +      headers: {
    +        'X-Parse-Application-Id': 'test',
    +        'X-Parse-REST-API-Key': 'rest',
    +        'X-Parse-Session-Token': sessionToken,
    +        'Content-Type': 'application/json',
    +      },
    +      body: {
    +        sessionToken: null,
    +      },
    +    }).catch(e => e);
    +
    +    expect(updateRes.data.code).toBe(Parse.Error.INVALID_KEY_NAME);
    +  });
    +
       describe('PUT /sessions/me', () => {
         it('should return error with invalid session token', async () => {
           const response = await request({
    
  • src/RestWrite.js+4 4 modified
    @@ -1235,13 +1235,13 @@ RestWrite.prototype.handleSession = function () {
       if (this.query) {
         if (this.data.user && !this.auth.isMaster && this.data.user.objectId != this.auth.user.id) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: user');
    -    } else if (this.data.installationId) {
    +    } else if ('installationId' in this.data) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: installationId');
    -    } else if (this.data.sessionToken) {
    +    } else if ('sessionToken' in this.data) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: sessionToken');
    -    } else if (this.data.expiresAt && !this.auth.isMaster && !this.auth.isMaintenance) {
    +    } else if ('expiresAt' in this.data && !this.auth.isMaster && !this.auth.isMaintenance) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: expiresAt');
    -    } else if (this.data.createdWith && !this.auth.isMaster && !this.auth.isMaintenance) {
    +    } else if ('createdWith' in this.data && !this.auth.isMaster && !this.auth.isMaintenance) {
           throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'Invalid key name: createdWith');
         }
         if (!this.auth.isMaster) {
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.