VYPR
High severityNVD Advisory· Published Sep 30, 2021· Updated Aug 4, 2024

LiveQuery publishes user session tokens

CVE-2021-41109

Description

Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Prior to version 4.10.4, for regular (non-LiveQuery) queries, the session token is removed from the response, but for LiveQuery payloads it is currently not. If a user has a LiveQuery subscription on the Parse.User class, all session tokens created during user sign-ups will be broadcast as part of the LiveQuery payload. A patch in version 4.10.4 removes session tokens from the LiveQuery payload. As a workaround, set user.acl(new Parse.ACL()) in a beforeSave trigger to make the user private already on sign-up.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
parse-servernpm
< 4.10.44.10.4

Affected products

1

Patches

1
4ac4b7f71002

Merge pull request from GHSA-7pr3-p5fm-8r9x

6 files changed · +121 6
  • CHANGELOG.md+10 4 modified
    @@ -1,5 +1,11 @@
     # Parse Server Changelog
     
    +## 4.10.4
    +[Full Changelog](https://github.com/parse-community/parse-server/compare/4.10.3...4.10.4)
    +
    +### Security Fixes
    +- Strip out sessionToken when LiveQuery is used on Parse.User (Daniel Blyth) [GHSA-7pr3-p5fm-8r9x](https://github.com/parse-community/parse-server/security/advisories/GHSA-7pr3-p5fm-8r9x)
    +
     # 4.10.3
     
     ## Security Fixes
    @@ -24,15 +30,15 @@
     
     *Versions >4.5.2 and <4.10.0 are skipped.*
     
    -> ⚠️ A security incident caused a number of incorrect version tags to be pushed to the Parse Server repository. These version tags linked to a personal fork of a contributor who had write access to the repository. The code to which these tags linked has not been reviewed or approved by Parse Platform. Even though no releases were published with these incorrect versions, it was possible to define a Parse Server dependency that pointed to these version tags, for example if you defined this dependency: 
    +> ⚠️ A security incident caused a number of incorrect version tags to be pushed to the Parse Server repository. These version tags linked to a personal fork of a contributor who had write access to the repository. The code to which these tags linked has not been reviewed or approved by Parse Platform. Even though no releases were published with these incorrect versions, it was possible to define a Parse Server dependency that pointed to these version tags, for example if you defined this dependency:
     > ```js
     > "parse-server": "git@github.com:parse-community/parse-server.git#4.9.3"
     > ```
    -> 
    +>
     > We have since deleted the incorrect version tags, but they may still show up if your personal fork on GitHub or locally. We do not know when these tags have been pushed to the Parse Server repository, but we first became aware of this issue on July 21, 2021. We are not aware of any malicious code or concerns related to privacy, security or legality (e.g. proprietary code). However, it has been reported that some functionality does not work as expected and the introduction of security vulnerabilities cannot be ruled out.
     >
    -> You may be also affected if you used the Bitnami image for Parse Server. Bitnami picked up the incorrect version tag `4.9.3` and published a new Bitnami image for Parse Server. 
    -> 
    +> You may be also affected if you used the Bitnami image for Parse Server. Bitnami picked up the incorrect version tag `4.9.3` and published a new Bitnami image for Parse Server.
    +>
     >**If you are using any of the affected versions, we urgently recommend to upgrade to version `4.10.0`.**
     
     # 4.5.2
    
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "parse-server",
    -  "version": "4.10.3",
    +  "version": "4.10.4",
       "description": "An express module providing a Parse-compatible API server",
       "main": "lib/index.js",
       "repository": {
    
  • package-lock.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "parse-server",
    -  "version": "4.10.3",
    +  "version": "4.10.4",
       "lockfileVersion": 1,
       "requires": true,
       "dependencies": {
    
  • spec/ParseLiveQuery.spec.js+46 0 modified
    @@ -928,6 +928,52 @@ describe('ParseLiveQuery', function () {
         done();
       });
     
    +  it('should strip out session token in LiveQuery', async () => {
    +    await reconfigureServer({
    +      liveQuery: { classNames: ['_User'] },
    +      startLiveQueryServer: true,
    +      verbose: false,
    +      silent: true,
    +    });
    +
    +    const user = new Parse.User();
    +    user.setUsername('username');
    +    user.setPassword('password');
    +    user.set('foo', 'bar');
    +
    +    const query = new Parse.Query(Parse.User);
    +    query.equalTo('foo', 'bar');
    +    const subscription = await query.subscribe();
    +
    +    const events = ['create', 'update', 'enter', 'leave', 'delete'];
    +    const response = (obj, prev) => {
    +      expect(obj.get('sessionToken')).toBeUndefined();
    +      expect(obj.sessionToken).toBeUndefined();
    +      expect(prev?.sessionToken).toBeUndefined();
    +      if (prev && prev.get) {
    +        expect(prev.get('sessionToken')).toBeUndefined();
    +      }
    +    };
    +    const calls = {};
    +    for (const key of events) {
    +      calls[key] = response;
    +      spyOn(calls, key).and.callThrough();
    +      subscription.on(key, calls[key]);
    +    }
    +    await user.signUp();
    +    user.unset('foo');
    +    await user.save();
    +    user.set('foo', 'bar');
    +    await user.save();
    +    user.set('yolo', 'bar');
    +    await user.save();
    +    await user.destroy();
    +    await new Promise(resolve => process.nextTick(resolve));
    +    for (const key of events) {
    +      expect(calls[key]).toHaveBeenCalled();
    +    }
    +  });
    +
       afterEach(async function (done) {
         const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
         client.close();
    
  • spec/ParseUser.spec.js+45 0 modified
    @@ -3929,6 +3929,51 @@ describe('Parse.User testing', () => {
         }
       });
     
    +  it('should strip out authdata in LiveQuery', async () => {
    +    const provider = getMockFacebookProvider();
    +    Parse.User._registerAuthenticationProvider(provider);
    +
    +    await reconfigureServer({
    +      liveQuery: { classNames: ['_User'] },
    +      startLiveQueryServer: true,
    +      verbose: false,
    +      silent: true,
    +    });
    +
    +    const query = new Parse.Query(Parse.User);
    +    query.doesNotExist('foo');
    +    const subscription = await query.subscribe();
    +
    +    const events = ['create', 'update', 'enter', 'leave', 'delete'];
    +    const response = (obj, prev) => {
    +      expect(obj.get('authData')).toBeUndefined();
    +      expect(obj.authData).toBeUndefined();
    +      expect(prev?.authData).toBeUndefined();
    +      if (prev && prev.get) {
    +        expect(prev.get('authData')).toBeUndefined();
    +      }
    +    };
    +    const calls = {};
    +    for (const key of events) {
    +      calls[key] = response;
    +      spyOn(calls, key).and.callThrough();
    +      subscription.on(key, calls[key]);
    +    }
    +    const user = await Parse.User._logInWith('facebook');
    +
    +    user.set('foo', 'bar');
    +    await user.save();
    +    user.unset('foo');
    +    await user.save();
    +    user.set('yolo', 'bar');
    +    await user.save();
    +    await user.destroy();
    +    await new Promise(resolve => process.nextTick(resolve));
    +    for (const key of events) {
    +      expect(calls[key]).toHaveBeenCalled();
    +    }
    +  });
    +
       describe('issue #4897', () => {
         it_only_db('mongo')('should be able to login with a legacy user (no ACL)', async () => {
           // This issue is a side effect of the locked users and legacy users which don't have ACL's
    
  • src/LiveQuery/ParseLiveQueryServer.js+18 0 modified
    @@ -179,6 +179,14 @@ class ParseLiveQueryServer {
                     deletedParseObject = res.object.toJSON();
                     deletedParseObject.className = className;
                   }
    +              if (
    +                (deletedParseObject.className === '_User' ||
    +                  deletedParseObject.className === '_Session') &&
    +                !client.hasMasterKey
    +              ) {
    +                delete deletedParseObject.sessionToken;
    +                delete deletedParseObject.authData;
    +              }
                   client.pushDelete(requestId, deletedParseObject);
                 })
                 .catch(error => {
    @@ -315,6 +323,16 @@ class ParseLiveQueryServer {
                       originalParseObject = res.original.toJSON();
                       originalParseObject.className = res.original.className || className;
                     }
    +                if (
    +                  (currentParseObject.className === '_User' ||
    +                    currentParseObject.className === '_Session') &&
    +                  !client.hasMasterKey
    +                ) {
    +                  delete currentParseObject.sessionToken;
    +                  delete originalParseObject?.sessionToken;
    +                  delete currentParseObject.authData;
    +                  delete originalParseObject?.authData;
    +                }
                     const functionName =
                       'push' + message.event.charAt(0).toUpperCase() + message.event.slice(1);
                     if (client[functionName]) {
    

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

5

News mentions

0

No linked articles in our index yet.