Skip to content

SQL injection via query field name when using PostgreSQL (GHSA-c442-97qw-j6c6)#10177

Merged
mtrezza merged 4 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-c442-97qw-j6c6-9.x
Mar 11, 2026
Merged

SQL injection via query field name when using PostgreSQL (GHSA-c442-97qw-j6c6)#10177
mtrezza merged 4 commits intoparse-community:alphafrom
mtrezza:fix/GHSA-c442-97qw-j6c6-9.x

Conversation

@mtrezza
Copy link
Member

@mtrezza mtrezza commented Mar 11, 2026

Pull Request

Issue

SQL injection via query field name when using PostgreSQL (GHSA-c442-97qw-j6c6)

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

    • Improved validation and escaping of query field names to prevent malformed or unsafe database queries.
  • Tests

    • Added comprehensive tests for field-name and regex query validation, including nested/dotted fields, master-key behaviors, and protection of internal fields.
  • Refactor

    • Centralized rule definitions for query validation and internal-field access for more consistent and predictable behavior.

@parse-github-assistant
Copy link

parse-github-assistant bot commented Mar 11, 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 11, 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 11, 2026

📝 Walkthrough

Walkthrough

Adds PostgreSQL SQL-injection tests for $regex field names, refactors DatabaseController to a data-driven internalFields/queryOperators registry for key-name validation, and changes PostgresStorageAdapter field reference/escaping logic for dotted vs non-dotted fields.

Changes

Cohort / File(s) Summary
Security Test Suite
spec/vulnerabilities.spec.js
Adds tests covering $regex queries with malicious and legitimate field names, master vs non-master behaviors, nested/dotted fields, and internal-field update restrictions. Note: the new suite is present twice (duplicate block).
PostgreSQL Adapter: field reference & escaping
src/Adapters/Storage/Postgres/PostgresStorageAdapter.js
buildWhereClause now uses transformDotField for dotted fields but raw fieldName (with $index:name) for non-dotted fields; transformDotField now escapes double quotes in simple field names to produce safe SQL identifiers.
Query validation: data-driven internal fields/operators
src/Controllers/DatabaseController.js
Replaces hard-coded special-key lists with data-driven internalFields and queryOperators; derives specialQueryKeys and specialMasterQueryKeys and centralizes invalid-key detection and master-write derivation for updates.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(220,220,255,0.5)
    participant Client
  end
  rect rgba(220,255,220,0.5)
    participant DBController as DatabaseController
  end
  rect rgba(255,220,220,0.5)
    participant Adapter as PostgresStorageAdapter
  end
  rect rgba(240,240,240,0.5)
    participant PostgresDB as PostgreSQL
  end

  Client->>DBController: send query (filter with fieldName/$regex, masterKey?)
  DBController->>DBController: validateQuery(keyName, masterKey, internalFields, queryOperators)
  alt invalid key
    DBController-->>Client: return invalid-key error
  else allowed
    DBController->>Adapter: buildWhereClause(filter)
    alt fieldName contains dot
      Adapter->>Adapter: transformDotField(fieldName) -> quoted dotted identifier
    else non-dot field
      Adapter->>Adapter: escape double quotes in fieldName -> use raw $index:name
    end
    Adapter->>PostgresDB: execute SQL WHERE clause
    PostgresDB-->>Adapter: results
    Adapter-->>DBController: results
    DBController-->>Client: return results
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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 ❓ Inconclusive The PR description includes the issue link and completes the tests task, but omits the Approach section explaining the technical changes made. Add a detailed Approach section explaining how the SQL injection vulnerability is fixed (field name escaping, validation logic, etc.) to provide clarity on the implementation strategy.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main change: fixing a SQL injection vulnerability in PostgreSQL adapter via query field name handling.

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

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

2291-2316: Exercise the exact _email_verify_token + $regex path here.

$exists proves the allowlist, but it doesn’t hit the PostgreSQL $regex branch changed in this PR. Switching this to a trivial regex would make the regression test cover the exact master-only path.

🧪 Suggested tweak
       const response = await request({
         method: 'GET',
         url: `${serverURL}/classes/_User`,
         headers,
         qs: {
-          where: JSON.stringify({ _email_verify_token: { $exists: true } }),
+          where: JSON.stringify({ _email_verify_token: { $regex: '.*' } }),
         },
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/vulnerabilities.spec.js` around lines 2291 - 2316, The test currently
uses $exists to exercise the allowlist but not the PostgreSQL $regex branch;
update the request qs in the test "allows master key to query whitelisted
internal field _email_verify_token" to use a trivial regex on
_email_verify_token (e.g. { _email_verify_token: { $regex: '.*' } }) so the
request sent by request(...) hits the $regex code path; locate the test using
reconfigureServer, request, serverURL, and headers and replace the where clause
JSON.stringify payload accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 2291-2316: The test currently uses $exists to exercise the
allowlist but not the PostgreSQL $regex branch; update the request qs in the
test "allows master key to query whitelisted internal field _email_verify_token"
to use a trivial regex on _email_verify_token (e.g. { _email_verify_token: {
$regex: '.*' } }) so the request sent by request(...) hits the $regex code path;
locate the test using reconfigureServer, request, serverURL, and headers and
replace the where clause JSON.stringify payload accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9062add-fc49-47dc-9edd-9888df4d0b44

📥 Commits

Reviewing files that changed from the base of the PR and between c795c14 and 1c21d66.

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

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 11, 2026
@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.61%. Comparing base (4d48847) to head (28e3c07).
⚠️ Report is 4 commits behind head on alpha.

Files with missing lines Patch % Lines
...dapters/Storage/Postgres/PostgresStorageAdapter.js 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            alpha   #10177      +/-   ##
==========================================
- Coverage   92.61%   92.61%   -0.01%     
==========================================
  Files         192      192              
  Lines       16249    16256       +7     
  Branches      190      190              
==========================================
+ Hits        15049    15055       +6     
- Misses       1187     1188       +1     
  Partials       13       13              

☔ 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.

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 `@src/Controllers/DatabaseController.js`:
- Around line 62-80: The update validation is incorrectly allowing non-master
callers to use fields derived from internalFields[*].masterWrite via
specialKeysForUpdate; in DatabaseController.update you must gate acceptance of
those masterWrite internal keys behind the isMaster check (i.e., when building
or applying specialKeysForUpdate during update-key validation only include
masterWrite keys if isMaster is true), so that sensitive fields like
_email_verify_token, _perishable_token, _failed_login_count,
_account_lockout_expires_at, and _password_history are treated as master-only;
update the validation logic in DatabaseController.update to consult isMaster
before treating any key from specialKeysForUpdate as allowed for the caller.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 37e54f52-f4d0-4439-ac60-47fc7c5a1185

📥 Commits

Reviewing files that changed from the base of the PR and between 1c21d66 and 7226e4c.

📒 Files selected for processing (1)
  • src/Controllers/DatabaseController.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.

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

2330-2367: Internal fields list should match the registry in DatabaseController.

The test iterates through internal fields to verify non-master updates are rejected. Ensure this list stays synchronized with internalFields in DatabaseController.js. Consider extracting the field list to a shared constant or generating it dynamically from the registry to prevent drift.

Suggestion: Import field list from source

If the internalFields registry is exported from DatabaseController, the test could derive the field list:

const { internalFields } = require('../lib/Controllers/DatabaseController');
const masterWriteFields = Object.keys(internalFields).filter(k => internalFields[k].masterWrite);

This would keep tests automatically in sync with implementation changes.

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

In `@spec/vulnerabilities.spec.js` around lines 2330 - 2367, The hard-coded
internalFields array in the test should be sourced from the authoritative
registry in DatabaseController rather than duplicated; update the test to
require/import the registry (e.g., DatabaseController's internalFields or its
registry map) and derive the list to test (for example filter keys where
masterWrite is true) so the test uses the same symbols as DatabaseController
(internalFields, masterWriteFields) and stays in sync with implementation
changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@spec/vulnerabilities.spec.js`:
- Around line 2330-2367: The hard-coded internalFields array in the test should
be sourced from the authoritative registry in DatabaseController rather than
duplicated; update the test to require/import the registry (e.g.,
DatabaseController's internalFields or its registry map) and derive the list to
test (for example filter keys where masterWrite is true) so the test uses the
same symbols as DatabaseController (internalFields, masterWriteFields) and stays
in sync with implementation changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5488da10-15bb-49a9-bf66-46b51035136d

📥 Commits

Reviewing files that changed from the base of the PR and between 7226e4c and 28e3c07.

📒 Files selected for processing (2)
  • spec/vulnerabilities.spec.js
  • src/Controllers/DatabaseController.js

@mtrezza mtrezza changed the title fix: GHSA-c442-97qw-j6c6-9.x SQL injection via query field name when using PostgreSQL (GHSA-c442-97qw-j6c6) Mar 11, 2026
@mtrezza mtrezza merged commit b43b224 into parse-community:alpha Mar 11, 2026
22 of 24 checks passed
@mtrezza mtrezza deleted the fix/GHSA-c442-97qw-j6c6-9.x branch March 11, 2026 14:23
@parseplatformorg
Copy link
Contributor

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

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