Skip to content

fix: SQL Injection via dot-notation sub-key name in Increment operation on PostgreSQL (GHSA-gqpp-xgvh-9h7h)#10165

Merged
mtrezza merged 4 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-gqpp-xgvh-9h7h-v9
Mar 10, 2026
Merged

fix: SQL Injection via dot-notation sub-key name in Increment operation on PostgreSQL (GHSA-gqpp-xgvh-9h7h)#10165
mtrezza merged 4 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-gqpp-xgvh-9h7h-v9

Conversation

@mtrezza
Copy link
Member

@mtrezza mtrezza commented Mar 10, 2026

Pull Request

Issue

SQL Injection via dot-notation sub-key name in Increment operation on PostgreSQL (GHSA-gqpp-xgvh-9h7h)

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

    • Fixed a PostgreSQL issue where Increment operations with dot-notation sub-keys could be misinterpreted; field names with special characters are now handled safely to prevent unintended SQL behavior.
  • Tests

    • Added a PostgreSQL-only test suite covering multiple dot-notation sub-key name edge cases (single/double-quote and valid JSONB forms) plus a normal nested Increment verification.

@parse-github-assistant
Copy link

parse-github-assistant bot commented Mar 10, 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.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

Adds Postgres-targeted vulnerability tests for SQL injection via dot-notation sub-key names in Increment operations and introduces SQL string sanitization in the Postgres storage adapter to escape dot-field components and JSON key names.

Changes

Cohort / File(s) Summary
Vulnerability tests
spec/vulnerabilities.spec.js
Adds a new Postgres-only test suite (GHSA-gqpp-xgvh-9h7h) with four Increment tests exercising dot-notation sub-key names, including single- and double-quote payloads and a normal nested Increment check.
Postgres adapter sanitization
src/Adapters/Storage/Postgres/PostgresStorageAdapter.js
Adds escapeSqlString helper and applies it to sanitize dot-field components and dynamically constructed JSON key names used in Increment/aggregation SQL expressions to mitigate SQL injection via dot-notation keys.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The pull request description follows the required template with Issue section populated (linking to GHSA-gqpp-xgvh-9h7h), but the Approach section lacks implementation details and the Tasks checklist shows only tests were completed. Add details to the Approach section explaining how the SQL injection vulnerability was fixed (e.g., the new escapeSqlString helper and its application to dot-notation handling). Clarify whether other incomplete tasks are intentionally deferred or should be completed.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly and specifically describes the security fix being implemented, referencing the CVE identifier and the specific vulnerability type (SQL Injection via dot-notation sub-key in Increment operation on PostgreSQL), which directly aligns with the changes in the changeset.

✏️ 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.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented Mar 10, 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.

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: 1

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

1363-1400: Add a happy-path regression for a quoted sub-key.

The timing test proves the payload no longer executes, but it still passes if quoted sub-keys now fail fast instead of updating correctly. Please add a positive case like stats.o'clock and assert the nested value increments, so the new escaping path is covered end-to-end.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/vulnerabilities.spec.js` around lines 1363 - 1400, Add a positive
regression test that mirrors the timing test but verifies a quoted sub-key
updates correctly: within an it_only_db('postgres') block create a SubKeyTest
Parse.Object with a nested field like stats["o'clock"] (set to an initial
number), save it, send the same PUT request using the dotted quoted key
"stats.o'clock" with an Increment op and amount 1, assert the HTTP response is
200, then fetch the object via new Parse.Query('SubKeyTest').get(obj.id) and
assert the nested stats["o'clock"] value incremented by 1; place this alongside
the existing tests so the escaping path is covered end-to-end.
🤖 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/Postgres/PostgresStorageAdapter.js`:
- Around line 211-212: The JSON key embedded via CONCAT('{"${safeName}":',
...)::jsonb in updateObjectsByQuery is not JSON-escaped (escapeSqlString only
covers SQL), so keys with " or \ break JSON; update the logic that uses safeName
(and the same occurrences around lines noted) to either validate the key
strictly (e.g. allow only a safe subset like /^[A-Za-z0-9_-]+$/) or apply
JSON-string escaping for the key by replacing " and \ (and other necessary JSON
control chars) before embedding into the CONCAT expression; ensure you update
the same pattern used elsewhere and keep escapeSqlString for SQL escaping
separate from this JSON-key escaping.

---

Nitpick comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 1363-1400: Add a positive regression test that mirrors the timing
test but verifies a quoted sub-key updates correctly: within an
it_only_db('postgres') block create a SubKeyTest Parse.Object with a nested
field like stats["o'clock"] (set to an initial number), save it, send the same
PUT request using the dotted quoted key "stats.o'clock" with an Increment op and
amount 1, assert the HTTP response is 200, then fetch the object via new
Parse.Query('SubKeyTest').get(obj.id) and assert the nested stats["o'clock"]
value incremented by 1; place this alongside the existing tests so the escaping
path is covered end-to-end.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 52489f52-7268-4a23-996f-c620ec69fac2

📥 Commits

Reviewing files that changed from the base of the PR and between d306b02 and 4fab072.

📒 Files selected for processing (2)
  • spec/vulnerabilities.spec.js
  • src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 1363-1425: The tests named "does not execute injected SQL via
single quote in sub-key name", "does not execute injected SQL via double quote
in sub-key name", and "does not execute injected SQL via double quote crafted as
valid JSONB in sub-key name" only measure timing; change them to also assert
post-update semantics by either (a) inspecting the HTTP response/error shape
(e.g., expect a 4xx/5xx with a specific error code/message when the payload is
rejected) or (b) reloading the Parse.Object from the server after the PUT and
asserting the 'stats.counter' value remained unchanged (or incremented only by
expected amounts) to prove no SQL execution or silent corruption occurred—use
the same obj.id from the test and Parse query or a GET to
/1/classes/SubKeyTest/<id> to verify persisted contents.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5dd5778e-700e-40d1-a33d-0bf543ed25a7

📥 Commits

Reviewing files that changed from the base of the PR and between 4fab072 and 6bab8bb.

📒 Files selected for processing (1)
  • spec/vulnerabilities.spec.js

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.

♻️ Duplicate comments (1)
spec/vulnerabilities.spec.js (1)

1411-1435: ⚠️ Potential issue | 🟡 Minor

Assert the full stats object in the crafted-valid-JSONB case.

Line 1426 can still serialize into extra JSON members while leaving stats.counter at 0, so this assertion can pass even if the row was silently corrupted. Please assert the entire object shape here, or the expected rejection, instead of only the counter field.

🔎 Tighten the persisted-state assertion
-    const verify = await new Parse.Query('SubKeyTest').get(obj.id);
-    expect(verify.get('stats').counter).toBe(0);
+    const verify = await new Parse.Query('SubKeyTest').get(obj.id);
+    expect(verify.get('stats')).toEqual({ counter: 0 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/vulnerabilities.spec.js` around lines 1411 - 1435, The current test
"does not execute injected SQL via double quote crafted as valid JSONB in
sub-key name" only asserts verify.get('stats').counter which can miss silent
corruption; update the test to assert the entire persisted stats object shape
(e.g., assert verify.get('stats') equals { counter: 0 } or use a deep-equality
matcher) or assert the request was rejected, ensuring the full object (not just
the counter field) is validated after the PUT; locate the test by its
description and the Parse.Query('SubKeyTest') / verify.get('stats') usage and
replace the single-field expectation with a deep equality check on the whole
stats object.
🧹 Nitpick comments (1)
spec/vulnerabilities.spec.js (1)

1356-1456: Suggested PR title: fix(security): sanitize Postgres Increment sub-key names against SQL injection

This would read well in the changelog and matches the scope of the change.

Based on learnings: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/vulnerabilities.spec.js` around lines 1356 - 1456, Update the pull
request title to the suggested Angular-style changelog entry: "fix(security):
sanitize Postgres Increment sub-key names against SQL injection" so it clearly
reflects the scope; use this exact phrasing as the PR title (following the
recommended Angular-style format) instead of the current generic title. Ensure
the final PR title is applied to the branch/PR metadata before merging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 1411-1435: The current test "does not execute injected SQL via
double quote crafted as valid JSONB in sub-key name" only asserts
verify.get('stats').counter which can miss silent corruption; update the test to
assert the entire persisted stats object shape (e.g., assert verify.get('stats')
equals { counter: 0 } or use a deep-equality matcher) or assert the request was
rejected, ensuring the full object (not just the counter field) is validated
after the PUT; locate the test by its description and the
Parse.Query('SubKeyTest') / verify.get('stats') usage and replace the
single-field expectation with a deep equality check on the whole stats object.

---

Nitpick comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 1356-1456: Update the pull request title to the suggested
Angular-style changelog entry: "fix(security): sanitize Postgres Increment
sub-key names against SQL injection" so it clearly reflects the scope; use this
exact phrasing as the PR title (following the recommended Angular-style format)
instead of the current generic title. Ensure the final PR title is applied to
the branch/PR metadata before merging.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bb1dd246-8a15-498c-a23c-5258aaa87c60

📥 Commits

Reviewing files that changed from the base of the PR and between 6bab8bb and 3f0755f.

📒 Files selected for processing (1)
  • spec/vulnerabilities.spec.js

@mtrezza mtrezza changed the title fix: GHSA-gqpp-xgvh-9h7h-v9 fix: SQL Injection via dot-notation sub-key name in Increment operation on PostgreSQL (GHSA-gqpp-xgvh-9h7h) Mar 10, 2026
@codecov
Copy link

codecov bot commented Mar 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.60%. Comparing base (03287cf) to head (3f0755f).
⚠️ Report is 3 commits behind head on alpha.

Additional details and impacted files
@@            Coverage Diff             @@
##            alpha   #10165      +/-   ##
==========================================
+ Coverage   92.59%   92.60%   +0.01%     
==========================================
  Files         192      192              
  Lines       16212    16214       +2     
  Branches      183      183              
==========================================
+ Hits        15011    15015       +4     
+ Misses       1189     1187       -2     
  Partials       12       12              

☔ 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 merged commit 169d692 into parse-community:alpha Mar 10, 2026
21 of 24 checks passed
parseplatformorg pushed a commit that referenced this pull request Mar 10, 2026
# [9.6.0-alpha.5](9.6.0-alpha.4...9.6.0-alpha.5) (2026-03-10)

### Bug Fixes

* 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))
@parseplatformorg
Copy link
Contributor

🎉 This change has been released in version 9.6.0-alpha.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:released-alpha Released as alpha version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants