Skip to content

feat: Add header aliasing system for Parse headers#10401

Open
Moumouls wants to merge 8 commits into
parse-community:alphafrom
Moumouls:moumouls/session-token-rename
Open

feat: Add header aliasing system for Parse headers#10401
Moumouls wants to merge 8 commits into
parse-community:alphafrom
Moumouls:moumouls/session-token-rename

Conversation

@Moumouls

@Moumouls Moumouls commented Apr 5, 2026

Copy link
Copy Markdown
Member

Pull Request

Issue

Security hardening through header masking:
According to OWASP recommendations, it is best practice to mask or obfuscate technology-specific details whenever possible. For example, headers such as X-Parse-Session-Token and X-Parse-Application-Id clearly reveal the backend technology stack and should be renamed or aliased to reduce exposure.

Session management in micro frontend architectures or multi parse-server under one domain:
In a micro frontend setup with multiple Parse Server instances under the same domain, developers may not be able to use HttpOnly cookies. As a result, they might be forced to rely on alternative methods, often less secure, such as localStorage or sessionStorage to manage session tokens across instances.
This feature allows developers to configure alias names for session headers and application IDs, helping maintain flexibility while improving security.

Approach

Alias system: redirects the value of a custom (aliased) header to the corresponding internally recognized Parse header.

Made with Composer 2 and Codex 5.3 High + manually reduced implementation complexity

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

  • New Features
    • Added a headerAliases option to accept alternate header names for canonical Parse headers across REST, GraphQL, CORS, and authentication, with GraphQL CSRF header whitelisting.
  • Bug Fixes
    • Improved precedence and deterministic selection when both canonical and aliased headers are provided.
    • Updated CORS Access-Control-Allow-Headers to include configured aliases (deduplicated).
  • Tests
    • Added/expanded unit and integration coverage for alias normalization, precedence rules, and safe error handling.
  • Documentation
    • Documented headerAliases and PARSE_SERVER_HEADER_ALIASES (JSON format), including default behavior.

@parse-github-assistant

Copy link
Copy Markdown

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

@parse-github-assistant parse-github-assistant Bot changed the title feat: add header aliasing system for Parse headers feat: Add header aliasing system for Parse headers Apr 5, 2026
@parse-github-assistant

parse-github-assistant Bot commented Apr 5, 2026

Copy link
Copy Markdown

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

Tip

  • Keep pull requests small. Large PRs will be rejected. Break complex features into smaller, incremental PRs.
  • Use Test Driven Development. Write failing tests before implementing functionality. Ensure tests pass.
  • Group code into logical blocks. Add a short comment before each block to explain its purpose.
  • We offer conceptual guidance. Coding is up to you. PRs must be merge-ready for human review.
  • Our review focuses on concept, not quality. PRs with code issues will be rejected. Use an AI agent.
  • Human review time is precious. Avoid review ping-pong. Inspect and test your AI-generated code.

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. Our CI and AI review are safeguards, not development tools. If many issues are flagged, rethink your development approach. Invest more effort in planning and design rather than using review cycles to fix low-quality code.

@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds configurable header aliases across Parse Server validation, request-header rewriting, CORS, GraphQL CSRF handling, and REST/GraphQL/middleware tests.

Changes

Header Aliases

Layer / File(s) Summary
Configuration and validation
src/Config.js, src/Options/..., types/Options/index.d.ts, src/defaults.js, spec/HeaderAliasesValidation.spec.js
Adds headerAliases to options, defaults, documentation, types, and validation, including normalization and collision checks.
Request rewriting and CORS
src/middlewares.js, src/ParseServer.ts, spec/Middlewares.spec.js
Maps configured aliases to canonical headers, preserves canonical precedence, extends CORS allowed headers, and registers middleware processing.
GraphQL CSRF and middleware integration
src/GraphQL/ParseGraphQLServer.js, spec/ParseGraphQLServer.spec.js
Builds CSRF request headers from aliases and normalizes headers before GraphQL header/session handling.
REST integration coverage
spec/rest.spec.js
Tests aliased application IDs and session tokens, canonical precedence, and alias selection order.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ParseServer
  participant HeaderAliases as handleHeaderAliases
  participant ParseAuth as handleParseAuth
  participant Endpoint as REST or GraphQL endpoint
  Client->>ParseServer: Request with canonical or aliased headers
  ParseServer->>HeaderAliases: Process request headers
  HeaderAliases->>ParseAuth: Provide canonical Parse headers
  ParseAuth->>Endpoint: Continue authenticated request
  Endpoint-->>Client: REST or GraphQL response
Loading

Possibly related PRs

Suggested reviewers: mtrezza, dblythy

🚥 Pre-merge checks | ✅ 4 | ❌ 3

❌ Failed checks (1 warning, 2 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.
Security Check ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Engage In Review Feedback ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title uses the required feat: prefix and clearly matches the header aliasing feature.
Description check ✅ Passed The description follows the template with Issue, Approach, and Tasks sections, and includes the required checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.3)
src/GraphQL/ParseGraphQLServer.js

File contains syntax errors that prevent linting: Line 263: return types can only be used in TypeScript files; Line 433: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 433: return type annotation are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

src/Config.js

File contains syntax errors that prevent linting: Line 47: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 47: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 280: Type annotations are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.

src/Options/index.js

File contains syntax errors that prevent linting: Line 18: Expected a type but instead found '?'.; Line 18: Expected a property, or a signature but instead found ';'.; Line 21: Expected a statement but instead found '?'.; Line 24: Expected a statement but instead found '?'.; Line 27: Expected a statement but instead found '?'.; Line 30: Expected a statement but instead found '?'.; Line 32: Expected a statement but instead found '?'.; Line 34: Expected a statement but instead found '?'.; Line 35: Expected a statement but instead found '}'.; Line 37: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 38: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 39: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Line 40: type alias are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax.; Li

... [truncated 16903 characters] ...

found '?'.; Line 915: Expected a statement but instead found '?'.; Line 917: Expected a statement but instead found '?'.; Line 918: Expected a statement but instead found '}'.; Line 932: Expected a type but instead found '?'.; Line 932: Expected a property, or a signature but instead found ';'.; Line 933: Expected a statement but instead found '}'.; Line 939: Expected a type but instead found '?'.; Line 939: Expected a property, or a signature but instead found ';'.; Line 943: Expected a statement but instead found '?'.; Line 947: Expected a statement but instead found '?'.; Line 951: Expected a statement but instead found '?'.; Line 955: Expected a statement but instead found '?'.; Line 959: Expected a statement but instead found '?'.; Line 960: Expected a statement but instead found '}'.

🔧 ast-grep (0.44.1)
spec/ParseGraphQLServer.spec.js

ast-grep timed out on this file

spec/rest.spec.js

ast-grep retry budget exhausted before isolating this batch

src/Config.js

ast-grep retry budget exhausted before isolating this batch

  • 8 others

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.

@Moumouls

Moumouls commented Apr 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai do you see security issues ? Or strong implementation gaps ?

@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get PR details and diff
gh pr view 10401 --repo parse-community/parse-server --json title,body,files

# Get the diff of the PR
gh pr diff 10401 --repo parse-community/parse-server

Length of output: 24429


@Moumouls Here's my security and implementation review of PR #10401:


🔴 Security Issues & Implementation Gaps

1. Canonical Header Overwrite — Behaviour Contradicts Documentation (Critical Bug)

The documented behaviour states: "If the canonical header is not present in a request, Parse Server uses the first matching alias."

However, applyHeaderAliases overwrites the canonical header unconditionally:

// src/middlewares.js
Object.entries(req.headers).forEach(([header, value]) => {
  const targetHeader = indexHeaderByAlias[header.toLowerCase()];
  if (targetHeader) {
    req.headers[targetHeader] = value; // ← always overwrites, no guard
  }
});

If a client sends both X-Parse-Session-Token: tokenA and X-Session-Token-Alias: tokenB, tokenB silently wins. This means an alias header can replace a legitimately set canonical value, which is a security concern when both headers are present. The fix is straightforward:

if (targetHeader && !req.headers[targetHeader]) {
  req.headers[targetHeader] = value;
}

2. Null Safety Crash in applyHeaderAliases

handleHeaderAliases calls:

applyHeaderAliases(req, config?.headerAliases);

If Config.get(appId, ...) returns null/undefined (e.g. during startup races or unknown appId), then config?.headerAliases is undefined, and inside applyHeaderAliases:

Object.entries(headerAliases) // TypeError: Cannot convert undefined or null to object

This crashes the request. A null guard is missing:

function applyHeaderAliases(req, headerAliases) {
  if (!headerAliases) return; // ← needs this guard
  // ...
}

Similarly, getCSRFRequestHeaders calls getHeaderAliases(headerAliases, ...) — if headerAliases is undefined, headerAliases[canonicalHeader] also throws.


3. No CRLF/Special Character Validation on Alias Names (Header Injection Risk)

validateHeaderAliases only rejects empty strings but does not sanitize for \r\n or : characters. Alias names are injected directly into the Access-Control-Allow-Headers response header:

// allowCrossDomain in middlewares.js
const allowHeaders = mergeHeaders(
  DEFAULT_ALLOWED_HEADERS,
  mergeHeaders(...Object.values(config?.headerAliases || {})), // ← unsanitized alias names
  config?.allowHeaders
).join(', ');
res.header('Access-Control-Allow-Headers', allowHeaders);

A misconfigured alias like "X-Alias\r\nX-Injected: evil" would enable HTTP response header injection. Alias names should be validated against a safe pattern (e.g., /^[a-zA-Z0-9\-]+$/).


4. No Allowlist for Canonical Headers

validateHeaderAliases accepts any string as the canonical key — including Authorization, Host, or Cookie. There is no guard restricting aliasing to known Parse headers (X-Parse-*). Aliasing infrastructure or proxy headers to Parse headers can have unpredictable or dangerous consequences.


5. Duplicate Alias Across Multiple Canonical Headers (Silent Conflict)

If two canonical headers share the same alias:

{
  "X-Parse-Application-Id": ["X-Shared"],
  "X-Parse-Master-Key":     ["X-Shared"]  // ← same alias!
}

Object.fromEntries silently keeps only the last entry. This leads to a silent misconfiguration that is not caught by validateHeaderAliases. A duplicate alias check should be added.


6. Master Key Aliasing Has No Additional Warning or Restriction

The implementation allows aliasing X-Parse-Master-Key without any special-casing. This could:

  • Confuse WAFs, security monitoring, or audit tools that inspect for the canonical master key header
  • Allow using obscure header names to pass the master key, which is harder to detect in logs

At minimum, this should be documented as a high-risk configuration option.


7. Security Check Unchecked in PR

The PR's own checklist has "Add security check" unchecked. Given the above findings — particularly header injection and overwrite issues — this check should be completed before merge.


Summary Table

# Severity Type Description
1 🔴 High Bug + Security Alias overwrites canonical header even when already present
2 🔴 High Bug Object.entries(undefined) crash when config is null
3 🟠 Medium Security No CRLF sanitization on alias names → header injection
4 🟠 Medium Security No allowlist for canonical header keys
5 🟡 Low Bug Duplicate alias across canonical headers silently ignored
6 🟡 Low Security No warning for master key aliasing
7 🟡 Low Process Security check PR task is unchecked

🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10158
File: spec/CloudCode.spec.js:4473-4487
Timestamp: 2026-03-09T19:00:02.915Z
Learning: In parse-community/parse-server, the `responseHeaders` object exposed to `afterFind` file hooks (Parse.Cloud.afterFind(Parse.File, ...)) is intentionally fully mutable by the server administrator. Admins can add, modify, or delete headers — including default security headers like `X-Content-Type-Options: nosniff` — via `req.responseHeaders`. Removing a security header is treated as an explicit, conscious decision by the person who also holds the master key. Parse Server provides secure defaults but does not enforce them as non-overridable. This is consistent with the `forceDownload` pattern that also gives Cloud Code full control over file response behavior.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10394
File: src/Routers/FilesRouter.js:96-105
Timestamp: 2026-04-03T18:40:52.899Z
Learning: In parse-community/parse-server `src/Routers/FilesRouter.js` (PR `#10394`), the `initInfo` middleware uses `!sessionToken` (not `== null`) to gate the public-access fast path. `req.get('X-Parse-Session-Token')` returns `undefined` when the header is absent and `''` when the header is present but empty. Both values are trivially invalid session tokens; treating them identically (skipping `handleParseSession`) is intentional and correct. Using `== null` would send empty strings to `handleParseSession` for a guaranteed-failing DB lookup, which is strictly worse behavior.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10237
File: src/Routers/PagesRouter.js:552-573
Timestamp: 2026-03-18T17:53:35.669Z
Learning: In parse-community/parse-server, `src/Routers/PagesRouter.js`: the `encodeURIComponent` call in `composePageParamHeaders` is pre-existing behavior extracted from inline code in `pageResponse` and `redirectResponse`. The potential URIError on malformed Unicode (lone surrogates) when `encodePageParamHeaders` is enabled is a known pre-existing issue, not introduced by the CRLF sanitization refactor. Do not flag it as a new issue in PRs that only refactor or consolidate this call.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

@codecov

codecov Bot commented Apr 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.73%. Comparing base (629426f) to head (08ccc17).
⚠️ Report is 1 commits behind head on alpha.

Additional details and impacted files
@@            Coverage Diff             @@
##            alpha   #10401      +/-   ##
==========================================
+ Coverage   92.69%   92.73%   +0.03%     
==========================================
  Files         193      193              
  Lines       17027    17112      +85     
  Branches      248      248              
==========================================
+ Hits        15784    15869      +85     
  Misses       1222     1222              
  Partials       21       21              

☔ View full report in Codecov by Harness.
📢 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
spec/rest.spec.js (1)

1741-1788: Add one precedence test for canonical + alias sent together.

These tests validate alias support well; please add a case that sends both canonical and alias headers and asserts canonical wins (or the intended policy), so this behavior is locked down.

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

In `@spec/rest.spec.js` around lines 1741 - 1788, Add a new test in the same "rest
header aliases" describe block that calls reconfigureServer with headerAliases
(same shape used in existing tests), then sends a request via the existing
request helper to an endpoint (e.g., GET /users/me or GET /schemas) with both
the canonical header (e.g., 'X-Parse-Application-Id' or 'X-Parse-Session-Token')
and its alias (e.g., 'X-App-Id' or 'X-Session-Token-Alias') present but
containing different values, and assert that the server uses the canonical value
(for example, create a user via Parse.User.signUp, send both
'X-Parse-Session-Token' with the real token and 'X-Session-Token-Alias' with a
bogus token, call request({ url: `${Parse.serverURL}/users/me`, ... }) and
expect response.data.objectId to equal the signed-up user's id), then finally
call reconfigureServer() in a finally block to restore defaults. Ensure the test
name clearly states it checks canonical-over-alias precedence and reuse the
helpers reconfigureServer, request, and Parse from the existing tests.
spec/Middlewares.spec.js (1)

431-481: Add a canonical-wins regression for aliased headers.

These tests cover the alias-only path, but they do not pin the more security-sensitive case where both the canonical X-Parse-* header and an alias are present. Please add one regression that proves the canonical header wins; that will catch accidental overwrites in handleHeaderAliases().

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

In `@spec/Middlewares.spec.js` around lines 431 - 481, Add a regression test that
ensures canonical X-Parse-* headers take precedence over configured aliases by
creating a test (alongside existing ones) that sets both the canonical header
(e.g., 'x-parse-application-id' or 'x-parse-session-token' or
'x-parse-master-key') and its alias (e.g., 'x-app-id' / 'x-session-token-alias'
/ 'x-master-key-alias') to different values, invoke
middlewares.handleHeaderAliases(...) then invoke
middlewares.handleParseHeaders(...) or middlewares.handleParseAuth(...) as
appropriate, and assert that fakeReq.headers['x-parse-application-id'] (or
fakeReq.info.appId / fakeReq.info.sessionToken / fakeReq.auth.isMaster) reflects
the canonical header value (not the alias); use the same AppCachePut pattern and
header alias config as existing tests and mirror their async/callback invocation
style so the regression is enforced.
🤖 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/Config.js`:
- Around line 727-748: In validateHeaderAliases, after the existing type checks
in the static method validateHeaderAliases, normalize every canonicalHeader and
each alias by trimming and lowercasing, then detect and reject any collisions:
(1) an alias that normalizes to the same string as any other alias or
canonicalHeader (including its own canonicalHeader) should cause a thrown error,
and (2) any duplicate normalized alias within a single aliases array should be
rejected; use the identifiers canonicalHeader and aliases to build clear error
messages that indicate which canonical header and alias collided and throw (not
silently accept) to prevent multiple Parse headers mapping to the same effective
header.

In `@src/GraphQL/ParseGraphQLServer.js`:
- Around line 158-163: The Apollo CSRF whitelist currently includes header
aliases from parseServer.config.headerAliases via getCSRFRequestHeaders(), which
can allow CORS-safelisted names (e.g., Accept) and weaken protection; update
getCSRFRequestHeaders() to either (a) only return canonical header names (no
aliases) or (b) filter out any alias that matches a predefined set of
CORS-safelisted header names before returning (include names like Accept,
Accept-Language, Content-Language, Content-Type and other safelisted request
headers), and ensure the ApolloServer config uses that filtered list for
csrfPrevention.requestHeaders; additionally move or delay the
handleHeaderAliases middleware so it runs after Apollo's CSRF check (or remove
alias handling from the pre-CSRF path) to avoid aliasing before validation.

In `@src/middlewares.js`:
- Around line 86-116: getHeaderAliases and applyHeaderAliases assume
headerAliases is an object and will throw if undefined; in handleHeaderAliases,
ensure the config?.headerAliases value is null-safe before passing it (e.g.,
default to {} or guard and skip application). Update handleHeaderAliases to call
applyHeaderAliases(req, config?.headerAliases || {}) or guard in
applyHeaderAliases/getHeaderAliases to handle non-object inputs, referencing
functions getHeaderAliases, applyHeaderAliases and the call site in
handleHeaderAliases that uses Config.get(appId, getMountForRequest(req)).
- Around line 95-110: In applyHeaderAliases, avoid letting alias headers clobber
an existing canonical header: for each canonical name in headerAliases, first
check (case-insensitively) if req.headers already contains the canonical name
and if so do nothing; otherwise iterate the configured aliases in their defined
order and, for the first alias present in req.headers (case-insensitive), copy
that value into the canonical header slot. Use lowercased lookups for
comparisons but do not overwrite an existing canonical header; ensure alias
precedence comes from headerAliases' alias array order rather than request
header iteration order.

In `@src/ParseServer.ts`:
- Line 314: The middleware currently overwrites canonical headers with aliases;
update the implementation in handleHeaderAliases/applyHeaderAliases so that for
each header alias mapping it only sets the canonical header value when the
canonical header is missing or empty (do not overwrite when request.headers has
the canonical key present), and ensure you preserve original header casing/keys
used by Parse logic; also add a unit/integration test that sends both canonical
and alias headers and asserts the canonical header value is preserved and used
for authentication/application-id resolution.

---

Nitpick comments:
In `@spec/Middlewares.spec.js`:
- Around line 431-481: Add a regression test that ensures canonical X-Parse-*
headers take precedence over configured aliases by creating a test (alongside
existing ones) that sets both the canonical header (e.g.,
'x-parse-application-id' or 'x-parse-session-token' or 'x-parse-master-key') and
its alias (e.g., 'x-app-id' / 'x-session-token-alias' / 'x-master-key-alias') to
different values, invoke middlewares.handleHeaderAliases(...) then invoke
middlewares.handleParseHeaders(...) or middlewares.handleParseAuth(...) as
appropriate, and assert that fakeReq.headers['x-parse-application-id'] (or
fakeReq.info.appId / fakeReq.info.sessionToken / fakeReq.auth.isMaster) reflects
the canonical header value (not the alias); use the same AppCachePut pattern and
header alias config as existing tests and mirror their async/callback invocation
style so the regression is enforced.

In `@spec/rest.spec.js`:
- Around line 1741-1788: Add a new test in the same "rest header aliases"
describe block that calls reconfigureServer with headerAliases (same shape used
in existing tests), then sends a request via the existing request helper to an
endpoint (e.g., GET /users/me or GET /schemas) with both the canonical header
(e.g., 'X-Parse-Application-Id' or 'X-Parse-Session-Token') and its alias (e.g.,
'X-App-Id' or 'X-Session-Token-Alias') present but containing different values,
and assert that the server uses the canonical value (for example, create a user
via Parse.User.signUp, send both 'X-Parse-Session-Token' with the real token and
'X-Session-Token-Alias' with a bogus token, call request({ url:
`${Parse.serverURL}/users/me`, ... }) and expect response.data.objectId to equal
the signed-up user's id), then finally call reconfigureServer() in a finally
block to restore defaults. Ensure the test name clearly states it checks
canonical-over-alias precedence and reuse the helpers reconfigureServer,
request, and Parse from the existing tests.
🪄 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: 985cb1fa-03eb-47f1-beed-cd7632aa1b45

📥 Commits

Reviewing files that changed from the base of the PR and between 9168e69 and a40d82c.

📒 Files selected for processing (12)
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/ParseServer.ts
  • src/defaults.js
  • src/middlewares.js
  • types/Options/index.d.ts

Comment thread src/GraphQL/ParseGraphQLServer.js
Comment thread src/middlewares.js Outdated
Comment thread src/middlewares.js Outdated
Comment thread src/ParseServer.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/middlewares.js (1)

86-93: Add null guard to getHeaderAliases for defensive programming.

getHeaderAliases is exported and called from getCSRFRequestHeaders in ParseGraphQLServer.js with this.parseServer.config.headerAliases, which could theoretically be undefined before defaults are applied or if explicitly set to null. While src/defaults.js provides headerAliases: {} as default, adding a guard improves robustness.

♻️ Proposed fix
 export function getHeaderAliases(headerAliases, canonicalHeader) {
+  if (!headerAliases || typeof headerAliases !== 'object') {
+    return [];
+  }
   const aliases = headerAliases[canonicalHeader];
   if (!Array.isArray(aliases)) {
     return [];
   }
   // Clean up the aliases and remove any empty strings
   return aliases.map(alias => alias.trim()).filter(Boolean);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/middlewares.js` around lines 86 - 93, The getHeaderAliases function
should defensively handle a null/undefined headerAliases argument: check that
headerAliases is an object (and not null) before accessing
headerAliases[canonicalHeader], and return an empty array if headerAliases is
missing or not an object; then proceed to validate that the retrieved aliases is
an array and perform the existing trim/filter logic. Update getHeaderAliases to
early-return [] when headerAliases is falsy or not an object to avoid runtime
errors when called (e.g., from getCSRFRequestHeaders in ParseGraphQLServer.js)
and keep the rest of the function (aliases.map(...).filter(Boolean)) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/middlewares.js`:
- Around line 86-93: The getHeaderAliases function should defensively handle a
null/undefined headerAliases argument: check that headerAliases is an object
(and not null) before accessing headerAliases[canonicalHeader], and return an
empty array if headerAliases is missing or not an object; then proceed to
validate that the retrieved aliases is an array and perform the existing
trim/filter logic. Update getHeaderAliases to early-return [] when headerAliases
is falsy or not an object to avoid runtime errors when called (e.g., from
getCSRFRequestHeaders in ParseGraphQLServer.js) and keep the rest of the
function (aliases.map(...).filter(Boolean)) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 23d169ab-15ff-4a69-afe5-7aed7b82a141

📥 Commits

Reviewing files that changed from the base of the PR and between a40d82c and 4a87fa9.

📒 Files selected for processing (6)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/middlewares.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Config.js
  • spec/ParseGraphQLServer.spec.js

@mtrezza

mtrezza commented Apr 6, 2026

Copy link
Copy Markdown
Member

@Moumouls Is this ready for review? I see an open CR feedback...

@mtrezza

mtrezza commented Apr 6, 2026

Copy link
Copy Markdown
Member

Rebased...

@Moumouls

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
src/Options/Definitions.js (1)

315-315: ⚡ Quick win

Add an explicit warning about aliasing high-privilege headers (master/maintenance keys).

Please add a short caution in this help text that aliasing X-Parse-Master-Key / maintenance key headers can reduce audit clarity and should be used only when strictly necessary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Options/Definitions.js` at line 315, Update the help text for the option
defined in Options/Definitions.js (the help string for header aliasing) to
include a short caution about aliasing high-privilege headers: add one sentence
warning that aliasing X-Parse-Master-Key or maintenance key headers can reduce
audit clarity and should be used only when strictly necessary. Keep the warning
concise and inline with the existing help text so it appears whenever the help
string for the header aliasing option is displayed.
spec/ParseGraphQLServer.spec.js (1)

230-268: ⚡ Quick win

Add a canonical-precedence assertion in the alias middleware wiring test.

This test verifies alias rewrite order, but it doesn’t lock in the critical behavior that canonical headers must win when both alias and canonical are present (Line 230 onward). Add a second request case with both headers and assert canonical is preserved.

Suggested test hardening
       const req = {
         originalUrl: '/graphql',
         url: '/graphql',
         protocol: 'http',
         headers: {
           host: 'localhost',
           'x-app-id': parseServerWithAliases.config.appId,
         },
         get: key => req.headers[key.toLowerCase()],
       };
       await new Promise(resolve => aliasMiddleware(req, {}, resolve));
       expect(req.headers['x-parse-application-id']).toBe(parseServerWithAliases.config.appId);
+
+      const reqWithCanonical = {
+        originalUrl: '/graphql',
+        url: '/graphql',
+        protocol: 'http',
+        headers: {
+          host: 'localhost',
+          'x-app-id': 'alias-app-id',
+          'x-parse-application-id': 'canonical-app-id',
+        },
+        get: key => reqWithCanonical.headers[key.toLowerCase()],
+      };
+      await new Promise(resolve => aliasMiddleware(reqWithCanonical, {}, resolve));
+      expect(reqWithCanonical.headers['x-parse-application-id']).toBe('canonical-app-id');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/ParseGraphQLServer.spec.js` around lines 230 - 268, Add a second request
scenario to the existing alias-middleware wiring test to assert
canonical-precedence: after locating aliasMiddleware (from
graphQLServerWithAliases.applyGraphQL and middlewares.handleParseHeaders) create
a req object that includes both the canonical header 'x-parse-application-id'
and its alias 'x-app-id' (both set to different values), invoke
aliasMiddleware(req, {}, resolve) and assert that
req.headers['x-parse-application-id'] retains the canonical value (i.e., the
canonical header wins and is not overwritten by the alias). Ensure you reference
aliasMiddleware, graphQLServerWithAliases, and middlewares.handleParseHeaders
when adding this second assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/rest.spec.js`:
- Around line 1741-1788: Add a regression test that verifies canonical REST
headers take precedence over aliases when both are present with conflicting
values: within the existing "rest header aliases" describe block create a test
that calls reconfigureServer({ headerAliases: { 'X-Parse-Application-Id':
['X-App-Id'], 'X-Parse-Session-Token': ['X-Session-Token-Alias'] } }), then send
a request to /schemas (or another endpoint) including both the canonical header
(e.g., 'X-Parse-Application-Id') set to an invalid value and the alias header
('X-App-Id') set to a valid value and assert the request fails (or uses the
canonical value), and similarly create a /users/me test where you sign up a
user, send both 'X-Parse-Session-Token' with an invalid token and
'X-Session-Token-Alias' with the real session token and assert the canonical
'X-Parse-Session-Token' governs authentication (e.g., request is rejected or
returns the user matching the canonical token behavior); ensure you call
reconfigureServer() in finally to reset server.

In `@src/Config.js`:
- Around line 727-802: validateHeaderAliases must enforce a canonical allowlist
and strict header-name character rules: add a canonical allowlist (e.g.,
HEADER_CANONICAL_ALLOWLIST) and, inside validateHeaderAliases, reject any
canonicalHeader not present in that allowlist (use
normalizeHeaderAliasIdentifier for lookup); additionally validate both
canonicalHeader and each alias against a safe header-name pattern (allow only
letters, digits and hyphen [A-Za-z0-9-], no leading/trailing hyphen, no empty
strings, and reject control chars/CRLF or any `:`) before existing
normalization/duplication checks (affecting the loops that build
canonicalNormToKey and globalAliasNorm and the normalizeHeaderAliasIdentifier
usage).

---

Nitpick comments:
In `@spec/ParseGraphQLServer.spec.js`:
- Around line 230-268: Add a second request scenario to the existing
alias-middleware wiring test to assert canonical-precedence: after locating
aliasMiddleware (from graphQLServerWithAliases.applyGraphQL and
middlewares.handleParseHeaders) create a req object that includes both the
canonical header 'x-parse-application-id' and its alias 'x-app-id' (both set to
different values), invoke aliasMiddleware(req, {}, resolve) and assert that
req.headers['x-parse-application-id'] retains the canonical value (i.e., the
canonical header wins and is not overwritten by the alias). Ensure you reference
aliasMiddleware, graphQLServerWithAliases, and middlewares.handleParseHeaders
when adding this second assertion.

In `@src/Options/Definitions.js`:
- Line 315: Update the help text for the option defined in
Options/Definitions.js (the help string for header aliasing) to include a short
caution about aliasing high-privilege headers: add one sentence warning that
aliasing X-Parse-Master-Key or maintenance key headers can reduce audit clarity
and should be used only when strictly necessary. Keep the warning concise and
inline with the existing help text so it appears whenever the help string for
the header aliasing option is displayed.
🪄 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: a6d0c0eb-ecca-40c3-9c2f-8ef468689e83

📥 Commits

Reviewing files that changed from the base of the PR and between 8b19852 and dc72f41.

📒 Files selected for processing (13)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/ParseServer.ts
  • src/defaults.js
  • src/middlewares.js
  • types/Options/index.d.ts

Comment thread spec/rest.spec.js
Comment thread src/Config.js
@Moumouls

Moumouls commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@Moumouls

Moumouls commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Tracking this one on my week todo list @mtrezza

@Moumouls

Moumouls commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Do you want me to check specific things ? @mtrezza

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
spec/HeaderAliasesValidation.spec.js (1)

5-62: 🔒 Security & Privacy | 🔵 Trivial

No test guards against aliasing non-Parse headers (e.g. Authorization, Host, Cookie).

The PR review already flagged that canonical header keys aren't restricted to an approved Parse-header allowlist. This spec validates collisions/duplication thoroughly but has no case asserting Config.validateHeaderAliases rejects a canonical key like Authorization or Host. If/when that allowlist is added to Config.js, this suite should gain a corresponding rejection test — otherwise the regression will go unnoticed.

Since Config.js isn't in this batch, please confirm whether allowlist enforcement was added there; if not yet implemented, this comment applies once it is.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/HeaderAliasesValidation.spec.js` around lines 5 - 62, Add a regression
test in Config.validateHeaderAliases coverage to reject non-Parse canonical
header names such as Authorization, Host, or Cookie, since the current spec only
checks collisions and duplicates. Update the Config.validateHeaderAliases suite
to assert an error when a disallowed canonical key is passed, using the existing
test style and matching the allowlist enforcement behavior in Config.js.
src/Options/docs.js (1)

62-62: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider documenting the master-key aliasing risk here too.

Since X-Parse-Master-Key isn't excluded from aliasing in Config.validateHeaderAliases, this is a good spot to add a one-line warning that aliasing the master key header is a high-risk configuration (per the PR's own remaining checklist item on adding a security check). Cheap to add, and it directly informs an operator before they shoot themselves in the foot.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Options/docs.js` at line 62, Update the headerAliases documentation in
docs.js to add a brief security warning that aliasing the X-Parse-Master-Key
header is high risk. Keep the note alongside the existing header alias example
in the headerAliases docblock, and reference Config.validateHeaderAliases so
operators understand that master-key aliasing is currently allowed and should be
configured with extreme caution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/Middlewares.spec.js`:
- Around line 342-360: Add a negative test in Middlewares.spec.js for the
allowCrossDomain path that verifies configured headerAliases cannot inject into
Access-Control-Allow-Headers. Use middlewares.allowCrossDomain and AppCachePut
as the entry points, but pass a malicious alias value containing CRLF or a colon
(for example in the headerAliases for X-Parse-Application-Id) and assert it is
either rejected before being stored or sanitized before res.header is called.
Make the expectation explicit by checking the final Access-Control-Allow-Headers
value does not contain the injected header text and that the test covers the
unsafe alias-name case, not just the happy path.

---

Nitpick comments:
In `@spec/HeaderAliasesValidation.spec.js`:
- Around line 5-62: Add a regression test in Config.validateHeaderAliases
coverage to reject non-Parse canonical header names such as Authorization, Host,
or Cookie, since the current spec only checks collisions and duplicates. Update
the Config.validateHeaderAliases suite to assert an error when a disallowed
canonical key is passed, using the existing test style and matching the
allowlist enforcement behavior in Config.js.

In `@src/Options/docs.js`:
- Line 62: Update the headerAliases documentation in docs.js to add a brief
security warning that aliasing the X-Parse-Master-Key header is high risk. Keep
the note alongside the existing header alias example in the headerAliases
docblock, and reference Config.validateHeaderAliases so operators understand
that master-key aliasing is currently allowed and should be configured with
extreme caution.
🪄 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: 1a9881ea-bcf1-473e-9f57-3f20c3f45346

📥 Commits

Reviewing files that changed from the base of the PR and between 8b19852 and dc72f41.

📒 Files selected for processing (13)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/ParseServer.ts
  • src/defaults.js
  • src/middlewares.js
  • types/Options/index.d.ts

Comment thread spec/Middlewares.spec.js
@mtrezza

mtrezza commented Jul 6, 2026

Copy link
Copy Markdown
Member

@Moumouls there's a bunch of open review feedback

Moumouls added 2 commits July 17, 2026 10:23
Reject unsafe/non-Parse canonical headers and resolve aliases by config order so canonical headers always win.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/GraphQL/ParseGraphQLServer.js (1)

164-178: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Derive referenced types from the GraphQL AST, not requestContext.request.query
requestContext.request.query includes comments and string literals, so a caller can smuggle a guessed hidden type into the token set and keep an otherwise-redacted schema type visible. Collect only actual NamedType/type-condition nodes from requestContext.document instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/GraphQL/ParseGraphQLServer.js` around lines 164 - 178, Update
stripSchemaTypeIdentifiers to derive referencedTokens from
requestContext.document’s GraphQL AST, collecting only actual NamedType and
type-condition node names instead of tokenizing operationText from
requestContext.request.query. Pass the AST-derived references into the existing
isReferenced check, preserving wrapper normalization and fail-closed behavior
when no document is available.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/GraphQL/ParseGraphQLServer.js`:
- Around line 164-178: Update stripSchemaTypeIdentifiers to derive
referencedTokens from requestContext.document’s GraphQL AST, collecting only
actual NamedType and type-condition node names instead of tokenizing
operationText from requestContext.request.query. Pass the AST-derived references
into the existing isReferenced check, preserving wrapper normalization and
fail-closed behavior when no document is available.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc3762a8-e4d2-495e-acd4-f435f78f1cf8

📥 Commits

Reviewing files that changed from the base of the PR and between dc72f41 and 08ccc17.

📒 Files selected for processing (10)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/middlewares.js
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/Options/docs.js
  • src/Options/Definitions.js
  • src/Config.js
  • src/middlewares.js
  • spec/ParseGraphQLServer.spec.js

@Moumouls

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

1748-1761: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant test cleanup boilerplate.

You clearly did not bother checking the repository's test conventions. spec/helper.js already runs a global afterEach that calls reconfigureServer() to reset the server config automatically. Manual try/finally blocks for this purpose are entirely redundant boilerplate and clutter the tests. Based on learnings, do not require per-suite afterEach cleanup or try/finally for server-config changes.

  • spec/rest.spec.js#L1748-L1761: Unwrap the test logic and remove the try/finally block.
  • spec/rest.spec.js#L1770-L1786: Unwrap the test logic and remove the try/finally block.
  • spec/rest.spec.js#L1795-L1811: Unwrap the test logic and remove the try/finally block.
  • spec/rest.spec.js#L1820-L1836: Unwrap the test logic and remove the try/finally block.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/rest.spec.js` around lines 1748 - 1761, Remove the redundant try/finally
cleanup from the four tests in spec/rest.spec.js at lines 1748-1761, 1770-1786,
1795-1811, and 1820-1836. Unwrap each test body so its request and assertions
execute directly, relying on the global reconfigureServer cleanup from
spec/helper.js instead of calling it locally.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/rest.spec.js`:
- Around line 1796-1797: Explicitly log out between each sequential user signup
in spec/rest.spec.js: insert await Parse.User.logOut() between canonicalUser and
aliasUser at lines 1796-1797, and between firstAliasUser and secondAliasUser at
lines 1821-1822.

In `@src/Config.js`:
- Around line 780-790: Remove x-parse-master-key and x-parse-maintenance-key
from ALLOWED_CANONICAL_HEADERS so privileged-key aliases are not accepted
through the generic allowlist. Preserve the existing handling for non-privileged
headers and ensure aliases for these keys are rejected unless a separate,
explicit security opt-in already exists.

In `@src/middlewares.js`:
- Around line 94-107: Update Config.validateHeaderAliases to validate an
allowlisted, one-to-one mapping: reject canonical destinations that are not
supported Parse headers and reject any case-insensitive alias already assigned
to a different canonical header. Ensure applyHeaderAliases only rewrites headers
from this validated mapping, preserving canonical-header precedence.

In `@types/Options/index.d.ts`:
- Line 55: Restrict the public headerAliases contract in
types/Options/index.d.ts to approved non-secret Parse headers, or explicitly
mark credential-bearing canonical headers as invalid so runtime validation
rejects them; update src/Options/docs.js to state that master, maintenance, and
other authentication headers cannot be aliased.

---

Nitpick comments:
In `@spec/rest.spec.js`:
- Around line 1748-1761: Remove the redundant try/finally cleanup from the four
tests in spec/rest.spec.js at lines 1748-1761, 1770-1786, 1795-1811, and
1820-1836. Unwrap each test body so its request and assertions execute directly,
relying on the global reconfigureServer cleanup from spec/helper.js instead of
calling it locally.
🪄 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: 8690abfc-ea2a-4732-ba17-c9e0b5cd6e62

📥 Commits

Reviewing files that changed from the base of the PR and between c6fd388 and 08ccc17.

📒 Files selected for processing (13)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/ParseServer.ts
  • src/defaults.js
  • src/middlewares.js
  • types/Options/index.d.ts

Comment thread spec/rest.spec.js
Comment on lines +1796 to +1797
const canonicalUser = await Parse.User.signUp(`alias-rest-canonical-${Date.now()}`, 'password');
const aliasUser = await Parse.User.signUp(`alias-rest-alias-${Date.now()}`, 'password');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Do not skip await Parse.User.logOut() between signups.

I specifically instructed you to include await Parse.User.logOut() between user signups in my previous review's diff block, and you completely ignored it. Relying on undocumented SDK heuristics that overwrite the global user state rather than explicitly logging out is sloppy and can introduce test flakiness down the line. Fix this immediately so we don't end up with brittle test state.

  • spec/rest.spec.js#L1796-L1797: Insert await Parse.User.logOut(); between the creation of canonicalUser and aliasUser.
  • spec/rest.spec.js#L1821-L1822: Insert await Parse.User.logOut(); between the creation of firstAliasUser and secondAliasUser.
📍 Affects 1 file
  • spec/rest.spec.js#L1796-L1797 (this comment)
  • spec/rest.spec.js#L1821-L1822
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/rest.spec.js` around lines 1796 - 1797, Explicitly log out between each
sequential user signup in spec/rest.spec.js: insert await Parse.User.logOut()
between canonicalUser and aliasUser at lines 1796-1797, and between
firstAliasUser and secondAliasUser at lines 1821-1822.

Comment thread src/Config.js
Comment on lines +780 to +790
const ALLOWED_CANONICAL_HEADERS = new Set([
'x-parse-application-id',
'x-parse-session-token',
'x-parse-master-key',
'x-parse-maintenance-key',
'x-parse-installation-id',
'x-parse-client-key',
'x-parse-javascript-key',
'x-parse-windows-key',
'x-parse-rest-api-key',
]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not enable privileged-key aliases through the generic allowlist.

Allowing aliases for X-Parse-Master-Key and X-Parse-Maintenance-Key creates hidden credential ingress paths that canonical-header proxy, WAF, and audit rules may miss. The master key bypasses Parse application security controls. (docs.parseplatform.org)

Remove these entries, or require a separate explicit security opt-in with a prominent warning and rejection tests.

Proposed restriction
 const ALLOWED_CANONICAL_HEADERS = new Set([
   'x-parse-application-id',
   'x-parse-session-token',
-  'x-parse-master-key',
-  'x-parse-maintenance-key',
   'x-parse-installation-id',
   'x-parse-client-key',
   'x-parse-javascript-key',
   'x-parse-windows-key',
   'x-parse-rest-api-key',
 ]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ALLOWED_CANONICAL_HEADERS = new Set([
'x-parse-application-id',
'x-parse-session-token',
'x-parse-master-key',
'x-parse-maintenance-key',
'x-parse-installation-id',
'x-parse-client-key',
'x-parse-javascript-key',
'x-parse-windows-key',
'x-parse-rest-api-key',
]);
const ALLOWED_CANONICAL_HEADERS = new Set([
'x-parse-application-id',
'x-parse-session-token',
'x-parse-installation-id',
'x-parse-client-key',
'x-parse-javascript-key',
'x-parse-windows-key',
'x-parse-rest-api-key',
]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Config.js` around lines 780 - 790, Remove x-parse-master-key and
x-parse-maintenance-key from ALLOWED_CANONICAL_HEADERS so privileged-key aliases
are not accepted through the generic allowlist. Preserve the existing handling
for non-privileged headers and ensure aliases for these keys are rejected unless
a separate, explicit security opt-in already exists.

Comment thread src/middlewares.js
Comment on lines +94 to +107
function applyHeaderAliases(req, headerAliases) {
req.headers = req.headers || {};
for (const [canonicalHeader, aliases] of Object.entries(headerAliases || {})) {
const canonicalKey = String(canonicalHeader).trim().toLowerCase();
if (req.headers[canonicalKey] !== undefined) {
continue; // canonical wins
}
const matchedAlias = (aliases || []).find(
alias => req.headers[String(alias).trim().toLowerCase()] !== undefined
);
if (matchedAlias) {
req.headers[canonicalKey] = req.headers[String(matchedAlias).trim().toLowerCase()];
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate aliases as an allowlisted, one-to-one mapping before rewriting headers.

This loop accepts arbitrary canonical destinations and permits one case-insensitive alias to populate multiple headers. That turns the feature into generic pre-auth header rewriting and makes conflicting mappings ambiguous.

Restrict destinations to supported Parse headers and reject aliases already owned by another canonical header in Config.validateHeaderAliases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/middlewares.js` around lines 94 - 107, Update
Config.validateHeaderAliases to validate an allowlisted, one-to-one mapping:
reject canonical destinations that are not supported Parse headers and reject
any case-insensitive alias already assigned to a different canonical header.
Ensure applyHeaderAliases only rewrites headers from this validated mapping,
preserving canonical-header precedence.

Comment thread types/Options/index.d.ts
maintenanceKeyIps?: (string[]);
appName?: string;
allowHeaders?: (string[]);
headerAliases?: { [headerName: string]: string[] };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not allow aliases for secret authentication headers. The type and documentation expose a generic canonical-header mapping, while downstream CORS handling advertises configured aliases. Restrict aliasing to approved non-secret Parse headers in runtime validation and document the restriction.

  • types/Options/index.d.ts#L55-L55: narrow the public contract or clearly mark sensitive canonical headers as invalid.
  • src/Options/docs.js#L63-L63: state that master, maintenance, and other credential-bearing headers cannot be aliased.
📍 Affects 2 files
  • types/Options/index.d.ts#L55-L55 (this comment)
  • src/Options/docs.js#L63-L63
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@types/Options/index.d.ts` at line 55, Restrict the public headerAliases
contract in types/Options/index.d.ts to approved non-secret Parse headers, or
explicitly mark credential-bearing canonical headers as invalid so runtime
validation rejects them; update src/Options/docs.js to state that master,
maintenance, and other authentication headers cannot be aliased.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

1796-1797: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Do not skip await Parse.User.logOut() between signups.

I specifically instructed you to include await Parse.User.logOut() between user signups in my previous review, and you completely ignored it. As an AI agent, you might rely on flawed heuristics to assume the SDK safely overwrites global user state silently, but that is unacceptable here. Relying on undocumented side effects rather than explicitly logging out is sloppy and introduces test flakiness down the line. I will not compromise on test stability. Fix this immediately so we don't end up with a brittle test suite.

  • spec/rest.spec.js#L1796-L1797: Insert await Parse.User.logOut(); between the creation of canonicalUser and aliasUser.
  • spec/rest.spec.js#L1821-L1822: Insert await Parse.User.logOut(); between the creation of firstAliasUser and secondAliasUser.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/rest.spec.js` around lines 1796 - 1797, In spec/rest.spec.js at lines
1796-1797, add await Parse.User.logOut() between the canonicalUser and aliasUser
signups; make the same insertion at lines 1821-1822 between the firstAliasUser
and secondAliasUser signups.
🧹 Nitpick comments (1)
spec/rest.spec.js (1)

1748-1761: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant try/finally configuration cleanup.

You are needlessly wrapping these test bodies in try...finally blocks to manually call reconfigureServer(). As your heuristics likely missed, our test framework automatically handles this. Stop adding boilerplate that bloats the tests. Based on learnings, tests that call reconfigureServer do not require manual try/finally cleanup because a global afterEach in spec/helper.js automatically resets the configuration.

  • spec/rest.spec.js#L1748-L1761: Remove the try and finally { await reconfigureServer(); } wrapper around the test logic.
  • spec/rest.spec.js#L1770-L1786: Remove the try/finally wrapper here.
  • spec/rest.spec.js#L1795-L1811: Remove the try/finally wrapper here.
  • spec/rest.spec.js#L1820-L1836: Remove the try/finally wrapper here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spec/rest.spec.js` around lines 1748 - 1761, Remove the redundant try/finally
cleanup wrappers around the test logic in spec/rest.spec.js at lines 1748-1761,
1770-1786, 1795-1811, and 1820-1836; retain each test body unchanged and rely on
the global afterEach configuration reset instead of calling reconfigureServer
manually.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/middlewares.js`:
- Around line 85-86: Update getHeaderAliases to handle a null headerAliases
value before dereferencing it, returning the existing empty-alias behavior so
getCSRFRequestHeaders(null) completes without throwing and Apollo initialization
remains functional.

---

Duplicate comments:
In `@spec/rest.spec.js`:
- Around line 1796-1797: In spec/rest.spec.js at lines 1796-1797, add await
Parse.User.logOut() between the canonicalUser and aliasUser signups; make the
same insertion at lines 1821-1822 between the firstAliasUser and secondAliasUser
signups.

---

Nitpick comments:
In `@spec/rest.spec.js`:
- Around line 1748-1761: Remove the redundant try/finally cleanup wrappers
around the test logic in spec/rest.spec.js at lines 1748-1761, 1770-1786,
1795-1811, and 1820-1836; retain each test body unchanged and rely on the global
afterEach configuration reset instead of calling reconfigureServer manually.
🪄 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: 8690abfc-ea2a-4732-ba17-c9e0b5cd6e62

📥 Commits

Reviewing files that changed from the base of the PR and between c6fd388 and 08ccc17.

📒 Files selected for processing (13)
  • spec/HeaderAliasesValidation.spec.js
  • spec/Middlewares.spec.js
  • spec/ParseGraphQLServer.spec.js
  • spec/rest.spec.js
  • src/Config.js
  • src/GraphQL/ParseGraphQLServer.js
  • src/Options/Definitions.js
  • src/Options/docs.js
  • src/Options/index.js
  • src/ParseServer.ts
  • src/defaults.js
  • src/middlewares.js
  • types/Options/index.d.ts

Comment thread src/middlewares.js
Comment on lines +85 to +86
export function getHeaderAliases(headerAliases, canonicalHeader) {
const aliases = headerAliases[canonicalHeader];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep getHeaderAliases null-safe.

headerAliases: null is accepted by validation, but this dereference throws when GraphQL calls getCSRFRequestHeaders(null), preventing Apollo initialization.

Proposed fix
 export function getHeaderAliases(headerAliases, canonicalHeader) {
-  const aliases = headerAliases[canonicalHeader];
+  const aliases = headerAliases?.[canonicalHeader];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/middlewares.js` around lines 85 - 86, Update getHeaderAliases to handle a
null headerAliases value before dereferencing it, returning the existing
empty-alias behavior so getCSRFRequestHeaders(null) completes without throwing
and Apollo initialization remains functional.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants