Skip to content

fix: NoSQL injection via token type in password reset and email verification endpoints (GHSA-vgjh-hmwf-c588)#10128

Merged
mtrezza merged 50 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-vgjh-hmwf-c588-v9
Mar 7, 2026
Merged

fix: NoSQL injection via token type in password reset and email verification endpoints (GHSA-vgjh-hmwf-c588)#10128
mtrezza merged 50 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-vgjh-hmwf-c588-v9

Conversation

@mtrezza
Copy link
Member

@mtrezza mtrezza commented Mar 7, 2026

Pull Request

Issue

NoSQL injection via token type in password reset and email verification endpoints (GHSA-vgjh-hmwf-c588)

Tasks

  • Add tests
  • Add changes to documentation (guides, repository pages, code comments)
  • Add security check
  • Add new Parse Error codes to Parse JS SDK

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced token validation in password reset workflows to ensure type consistency.
    • Improved token normalization in email verification flows.
  • Tests

    • Added comprehensive test coverage for token handling in password reset and email verification processes.

@parse-github-assistant
Copy link

I will reformat the title to use the proper commit message syntax.

@parse-github-assistant parse-github-assistant bot changed the title fix: ghsa vgjh hmwf c588 v9 fix: Ghsa vgjh hmwf c588 v9 Mar 7, 2026
@parse-github-assistant
Copy link

parse-github-assistant bot commented Mar 7, 2026

🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review.

Note

Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect.

Caution

Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented Mar 7, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

The changes enhance token handling and input validation in password reset and email verification flows. A new test suite validates rejection of regex injection operators in tokens, while code modifications normalize token types to strings and introduce runtime validation checks before downstream processing.

Changes

Cohort / File(s) Summary
Test Coverage Enhancements
spec/MongoTransform.spec.js, spec/RegexVulnerabilities.spec.js
Adds comprehensive test suites verifying rejection of token injection operators ($ne, $regex, $exists, $gt) in password reset flows and validating token type normalization in verification email resend flows. Includes trailing whitespace formatting adjustment.
Token Normalization & Validation
src/Routers/PagesRouter.js, src/Routers/UsersRouter.js
Normalizes token payload in resendVerificationEmail by converting non-string tokens to strings via toString(). Adds runtime validation in handleResetRequest to enforce string type requirement for tokens, throwing INVALID_VALUE on type mismatch.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description is incomplete, missing critical information in the Issue and Approach sections despite following the template structure. Fill in the Issue section with a clear reference to the security vulnerability (GHSA-vgjh-hmwf-c588) and provide the Approach section detailing the changes made to fix the NoSQL injection vulnerability in token handling.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the primary change: fixing a NoSQL injection vulnerability via token type handling in password reset and email verification endpoints, referencing the specific security advisory.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
spec/MongoTransform.spec.js (1)

696-742: Make these assertions specific to the intended rejection.

A generic toThrow() will also pass on unrelated parser failures. For a security regression like this, please assert the expected INVALID_VALUE message/code so these tests only pass for the token-type guard.

Example tightening
     it('should reject non-string value for _perishable_token', () => {
-      expect(() => {
-        transform.transformWhere(null, { _perishable_token: { $regex: '^a' } });
-      }).toThrow();
+      expect(() => {
+        transform.transformWhere(null, { _perishable_token: { $regex: '^a' } });
+      }).toThrowError(/_perishable_token must be a string/);
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/MongoTransform.spec.js` around lines 696 - 742, Update the tests that
currently use generic toThrow() for token-field rejections to assert the
specific INVALID_VALUE error from transform.transformWhere so unrelated parser
errors don't mask regressions: replace plain toThrow() checks for
_perishable_token and _email_verify_token (including cases for non-string, $ne
and $exists) with assertions that the thrown error includes the expected
INVALID_VALUE code/message (e.g., inspect the thrown error and expect error.code
or error.message to equal/contain "INVALID_VALUE") while leaving the
valid-string tests unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Adapters/Storage/Mongo/MongoTransform.js`:
- Around line 285-287: The current switch case for '_rperm' and '_wperm'
prematurely returns { key, value }, bypassing transformConstraint() and letting
operator objects reach Mongo; change this so only plain arrays are returned
directly (i.e., when value is an Array), while object values (operator objects)
are not returned early and instead fall through to be processed by
transformConstraint() so operator validation still runs; update the case in
MongoTransform.js (the '_rperm' / '_wperm' handling) to detect Array vs Object
and only short-circuit for arrays.

In `@src/Routers/PagesRouter.js`:
- Around line 111-112: The code currently calls a potentially user-controlled
toString() on req.body?.token (rawToken -> token) which can throw if token is an
object with a non-callable toString property; change the logic in the
PagesRouter request handler so you only accept string tokens and explicitly
reject or sanitize non-string inputs instead of calling toString(): e.g., check
typeof rawToken === 'string' and use that value (or set token = null/return a
fail response) for validation, referencing the rawToken and token variables in
the request handler to locate and replace the unsafe conversion.

---

Nitpick comments:
In `@spec/MongoTransform.spec.js`:
- Around line 696-742: Update the tests that currently use generic toThrow() for
token-field rejections to assert the specific INVALID_VALUE error from
transform.transformWhere so unrelated parser errors don't mask regressions:
replace plain toThrow() checks for _perishable_token and _email_verify_token
(including cases for non-string, $ne and $exists) with assertions that the
thrown error includes the expected INVALID_VALUE code/message (e.g., inspect the
thrown error and expect error.code or error.message to equal/contain
"INVALID_VALUE") while leaving the valid-string tests unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc81a297-10bc-4cc4-b1d2-85a0437fbf48

📥 Commits

Reviewing files that changed from the base of the PR and between bc45ef9 and fb69186.

📒 Files selected for processing (5)
  • spec/MongoTransform.spec.js
  • spec/RegexVulnerabilities.spec.js
  • src/Adapters/Storage/Mongo/MongoTransform.js
  • src/Routers/PagesRouter.js
  • src/Routers/UsersRouter.js

@codecov
Copy link

codecov bot commented Mar 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.70%. Comparing base (0e06b93) to head (cf72215).
⚠️ Report is 161 commits behind head on alpha.

Additional details and impacted files
@@            Coverage Diff             @@
##            alpha   #10128      +/-   ##
==========================================
+ Coverage   83.99%   92.70%   +8.70%     
==========================================
  Files         191      191              
  Lines       15939    15942       +3     
  Branches      180      180              
==========================================
+ Hits        13388    14779    +1391     
+ Misses       2535     1151    -1384     
+ Partials       16       12       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mtrezza mtrezza changed the title fix: Ghsa vgjh hmwf c588 v9 fix: NoSQL injection via token type in password reset and email verification endpoints (GHSA-vgjh-hmwf-c588) Mar 7, 2026
@mtrezza mtrezza merged commit b2f2317 into parse-community:alpha Mar 7, 2026
23 of 24 checks passed
parseplatformorg pushed a commit that referenced this pull request Mar 7, 2026
## [9.5.2-alpha.1](9.5.1...9.5.2-alpha.1) (2026-03-07)

### Bug Fixes

* NoSQL injection via token type in password reset and email verification endpoints ([GHSA-vgjh-hmwf-c588](GHSA-vgjh-hmwf-c588)) ([#10128](#10128)) ([b2f2317](b2f2317))
@mtrezza mtrezza deleted the fix/GHSA-vgjh-hmwf-c588-v9 branch March 7, 2026 19:18
@parseplatformorg
Copy link
Contributor

🎉 This change has been released in version 9.5.2-alpha.1

@parseplatformorg parseplatformorg added the state:released-alpha Released as alpha version label Mar 7, 2026
parseplatformorg pushed a commit that referenced this pull request Mar 22, 2026
# [9.6.0](9.5.1...9.6.0) (2026-03-22)

### Bug Fixes

*  LiveQuery `regexTimeout` default value not applied ([#10156](#10156)) ([416cfbc](416cfbc))
* Account lockout race condition allows bypassing threshold via concurrent requests ([#10266](#10266)) ([ff70fee](ff70fee))
* Account takeover via operator injection in authentication data identifier ([GHSA-5fw2-8jcv-xh87](GHSA-5fw2-8jcv-xh87)) ([#10185](#10185)) ([0d0a554](0d0a554))
* Add configurable batch request sub-request limit via option `requestComplexity.batchRequestLimit` ([#10265](#10265)) ([164ed0d](164ed0d))
* Auth data exposed via /users/me endpoint ([GHSA-37mj-c2wf-cx96](GHSA-37mj-c2wf-cx96)) ([#10278](#10278)) ([875cf10](875cf10))
* Auth provider validation bypass on login via partial authData ([GHSA-pfj7-wv7c-22pr](GHSA-pfj7-wv7c-22pr)) ([#10246](#10246)) ([98f4ba5](98f4ba5))
* Block dot-notation updates to authData sub-fields and harden login provider checks ([#10223](#10223)) ([12c24c6](12c24c6))
* Bypass of class-level permissions in LiveQuery ([GHSA-7ch5-98q2-7289](GHSA-7ch5-98q2-7289)) ([#10133](#10133)) ([98188d9](98188d9))
* Classes `_GraphQLConfig` and `_Audience` master key bypass via generic class routes ([GHSA-7xg7-rqf6-pw6c](GHSA-7xg7-rqf6-pw6c)) ([#10151](#10151)) ([1de4e43](1de4e43))
* Cloud function dispatch crashes server via prototype chain traversal ([GHSA-4263-jgmp-7pf4](GHSA-4263-jgmp-7pf4)) ([#10210](#10210)) ([286373d](286373d))
* Concurrent signup with same authentication creates duplicate users ([#10149](#10149)) ([853bfe1](853bfe1))
* Create CLP not enforced before user field validation on signup ([#10268](#10268)) ([a0530c2](a0530c2))
* Denial of service via unindexed database query for unconfigured auth providers ([GHSA-g4cf-xj29-wqqr](GHSA-g4cf-xj29-wqqr)) ([#10270](#10270)) ([fbac847](fbac847))
* Denial-of-service via unbounded query complexity in REST and GraphQL API ([GHSA-cmj3-wx7h-ffvg](GHSA-cmj3-wx7h-ffvg)) ([#10130](#10130)) ([0ae9c25](0ae9c25))
* Email verification resend page leaks user existence (GHSA-h29g-q5c2-9h4f) ([#10238](#10238)) ([fbda4cb](fbda4cb))
* Empty authData bypasses credential requirement on signup ([GHSA-wjqw-r9x4-j59v](GHSA-wjqw-r9x4-j59v)) ([#10219](#10219)) ([5dcbf41](5dcbf41))
* GraphQL WebSocket endpoint bypasses security middleware ([GHSA-p2x3-8689-cwpg](GHSA-p2x3-8689-cwpg)) ([#10189](#10189)) ([3ffba75](3ffba75))
* Incomplete JSON key escaping in PostgreSQL Increment on nested Object fields ([#10261](#10261)) ([a692873](a692873))
* Input type validation for query operators and batch path ([#10230](#10230)) ([a628911](a628911))
* Instance comparison with `instanceof` is not realm-safe ([#10225](#10225)) ([51efb1e](51efb1e))
* LDAP injection via unsanitized user input in DN and group filter construction ([GHSA-7m6r-fhh7-r47c](GHSA-7m6r-fhh7-r47c)) ([#10154](#10154)) ([5bbca7b](5bbca7b))
* LiveQuery bypasses CLP pointer permission enforcement ([GHSA-fph2-r4qg-9576](GHSA-fph2-r4qg-9576)) ([#10250](#10250)) ([6c3317a](6c3317a))
* LiveQuery subscription query depth bypass ([GHSA-6qh5-m6g3-xhq6](GHSA-6qh5-m6g3-xhq6)) ([#10259](#10259)) ([2126fe4](2126fe4))
* LiveQuery subscription with invalid regular expression crashes server ([GHSA-827p-g5x5-h86c](GHSA-827p-g5x5-h86c)) ([#10197](#10197)) ([0ae0eee](0ae0eee))
* Locale parameter path traversal in pages router ([#10242](#10242)) ([01fb6a9](01fb6a9))
* MFA recovery code single-use bypass via concurrent requests ([GHSA-2299-ghjr-6vjp](GHSA-2299-ghjr-6vjp)) ([#10275](#10275)) ([5e70094](5e70094))
* MFA recovery codes not consumed after use ([GHSA-4hf6-3x24-c9m8](GHSA-4hf6-3x24-c9m8)) ([#10170](#10170)) ([18abdd9](18abdd9))
* Missing audience validation in Keycloak authentication adapter ([GHSA-48mh-j4p5-7j9v](GHSA-48mh-j4p5-7j9v)) ([#10137](#10137)) ([78ef1a1](78ef1a1))
* Normalize HTTP method case in `allowMethodOverride` middleware ([#10262](#10262)) ([a248e8c](a248e8c))
* NoSQL injection via token type in password reset and email verification endpoints ([GHSA-vgjh-hmwf-c588](GHSA-vgjh-hmwf-c588)) ([#10128](#10128)) ([b2f2317](b2f2317))
* OAuth2 adapter app ID validation sends wrong token to introspection endpoint ([GHSA-69xg-f649-w5g2](GHSA-69xg-f649-w5g2)) ([#10187](#10187)) ([7f9f854](7f9f854))
* OAuth2 adapter shares mutable state across providers via singleton instance ([GHSA-2cjm-2gwv-m892](GHSA-2cjm-2gwv-m892)) ([#10183](#10183)) ([6009bc1](6009bc1))
* Parse Server OAuth2 authentication adapter account takeover via identity spoofing ([GHSA-fr88-w35c-r596](GHSA-fr88-w35c-r596)) ([#10145](#10145)) ([9cfd06e](9cfd06e))
* Parse Server role escalation and CLP bypass via direct `_Join table write ([GHSA-5f92-jrq3-28rc](GHSA-5f92-jrq3-28rc)) ([#10141](#10141)) ([22faa08](22faa08))
* Parse Server session token exfiltration via `redirectClassNameForKey` query parameter ([GHSA-6r2j-cxgf-495f](GHSA-6r2j-cxgf-495f)) ([#10143](#10143)) ([70b7b07](70b7b07))
* Password reset token single-use bypass via concurrent requests ([GHSA-r3xq-68wh-gwvh](GHSA-r3xq-68wh-gwvh)) ([#10216](#10216)) ([84db0a0](84db0a0))
* Protected field change detection oracle via LiveQuery watch parameter ([GHSA-qpc3-fg4j-8hgm](GHSA-qpc3-fg4j-8hgm)) ([#10253](#10253)) ([0c0a0a5](0c0a0a5))
* Protected fields bypass via dot-notation in query and sort ([GHSA-r2m8-pxm9-9c4g](GHSA-r2m8-pxm9-9c4g)) ([#10167](#10167)) ([8f54c54](8f54c54))
* Protected fields bypass via LiveQuery subscription WHERE clause ([GHSA-j7mm-f4rv-6q6q](GHSA-j7mm-f4rv-6q6q)) ([#10175](#10175)) ([4d48847](4d48847))
* Protected fields bypass via logical query operators ([GHSA-72hp-qff8-4pvv](GHSA-72hp-qff8-4pvv)) ([#10140](#10140)) ([be1d65d](be1d65d))
* Protected fields leak via LiveQuery afterEvent trigger ([GHSA-5hmj-jcgp-6hff](GHSA-5hmj-jcgp-6hff)) ([#10232](#10232)) ([6648500](6648500))
* Query condition depth bypass via pre-validation transform pipeline ([GHSA-9fjp-q3c4-6w3j](GHSA-9fjp-q3c4-6w3j)) ([#10257](#10257)) ([85994ef](85994ef))
* Rate limit bypass via batch request endpoint ([GHSA-775h-3xrc-c228](GHSA-775h-3xrc-c228)) ([#10147](#10147)) ([2766f4f](2766f4f))
* Rate limit bypass via HTTP method override and batch method spoofing ([#10234](#10234)) ([7d72d26](7d72d26))
* Rate limit user zone key fallback and batch request bypass ([#10214](#10214)) ([434ecbe](434ecbe))
* Revert accidental breaking default values for query complexity limits ([#10205](#10205)) ([ab8dd54](ab8dd54))
* Sanitize control characters in page parameter response headers ([#10237](#10237)) ([337ffd6](337ffd6))
* Schema poisoning via prototype pollution in deep copy ([GHSA-9ccr-fpp6-78qf](GHSA-9ccr-fpp6-78qf)) ([#10200](#10200)) ([b321423](b321423))
* Security fix fast-xml-parser from 5.5.5 to 5.5.6 ([#10235](#10235)) ([f521576](f521576))
* Security upgrade fast-xml-parser from 5.3.7 to 5.4.2 ([#10086](#10086)) ([b04ca5e](b04ca5e))
* Server crash via deeply nested query condition operators ([GHSA-9xp9-j92r-p88v](GHSA-9xp9-j92r-p88v)) ([#10202](#10202)) ([f44e306](f44e306))
* Session creation endpoint allows overwriting server-generated session fields ([GHSA-5v7g-9h8f-8pgg](GHSA-5v7g-9h8f-8pgg)) ([#10195](#10195)) ([7ccfb97](7ccfb97))
* Session token expiration unchecked on cache hit ([#10194](#10194)) ([a944203](a944203))
* Session update endpoint allows overwriting server-generated session fields ([GHSA-jc39-686j-wp6q](GHSA-jc39-686j-wp6q)) ([#10263](#10263)) ([ea68fc0](ea68fc0))
* SQL injection via `Increment` operation on nested object field in PostgreSQL ([GHSA-q3vj-96h2-gwvg](GHSA-q3vj-96h2-gwvg)) ([#10161](#10161)) ([8f82282](8f82282))
* SQL injection via aggregate and distinct field names in PostgreSQL adapter ([GHSA-p2w6-rmh7-w8q3](GHSA-p2w6-rmh7-w8q3)) ([#10272](#10272)) ([bdddab5](bdddab5))
* SQL injection via dot-notation field name in PostgreSQL ([GHSA-qpr4-jrj4-6f27](GHSA-qpr4-jrj4-6f27)) ([#10159](#10159)) ([ea538a4](ea538a4))
* SQL Injection via dot-notation sub-key name in `Increment` operation on PostgreSQL ([GHSA-gqpp-xgvh-9h7h](GHSA-gqpp-xgvh-9h7h)) ([#10165](#10165)) ([169d692](169d692))
* SQL injection via query field name when using PostgreSQL ([GHSA-c442-97qw-j6c6](GHSA-c442-97qw-j6c6)) ([#10181](#10181)) ([be281b1](be281b1))
* Stored cross-site scripting (XSS) via SVG file upload ([GHSA-hcj7-6gxh-24ww](GHSA-hcj7-6gxh-24ww)) ([#10136](#10136)) ([93b784d](93b784d))
* Stored XSS filter bypass via Content-Type MIME parameter and missing XML extension blocklist entries ([GHSA-42ph-pf9q-cr72](GHSA-42ph-pf9q-cr72)) ([#10191](#10191)) ([4f53ab3](4f53ab3))
* Stored XSS via file upload of HTML-renderable file types ([GHSA-v5hf-f4c3-m5rv](GHSA-v5hf-f4c3-m5rv)) ([#10162](#10162)) ([03287cf](03287cf))
* User enumeration via email verification endpoint ([GHSA-w54v-hf9p-8856](GHSA-w54v-hf9p-8856)) ([#10172](#10172)) ([936abd4](936abd4))
* Validate authData provider values in challenge endpoint ([#10224](#10224)) ([e5e1f5b](e5e1f5b))
* Validate body field types in request middleware ([#10209](#10209)) ([df69046](df69046))
* Validate session in middleware for non-GET requests to `/sessions/me` ([#10213](#10213)) ([2a9fdab](2a9fdab))
* Validate token type in PagesRouter to prevent type confusion errors ([#10212](#10212)) ([386a989](386a989))

### Features

* Add `enableProductPurchaseLegacyApi` option to disable legacy IAP validation ([#10228](#10228)) ([622ee85](622ee85))
* Add `protectedFieldsOwnerExempt` option to control `_User` class owner exemption for `protectedFields` ([#10280](#10280)) ([d5213f8](d5213f8))
* Add `X-Content-Type-Options: nosniff` header and customizable response headers for files via `Parse.Cloud.afterFind(Parse.File)` ([#10158](#10158)) ([28d11a3](28d11a3))
@parseplatformorg
Copy link
Contributor

🎉 This change has been released in version 9.6.0

@parseplatformorg parseplatformorg added the state:released Released as stable version label Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:released Released as stable version state:released-alpha Released as alpha version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants