Skip to content

Reject GET requests with a Content-Type other than application/json#8191

Merged
glasser merged 3 commits intomainfrom
get-content-type-validation
Mar 24, 2026
Merged

Reject GET requests with a Content-Type other than application/json#8191
glasser merged 3 commits intomainfrom
get-content-type-validation

Conversation

@glasser
Copy link
Copy Markdown
Member

@glasser glasser commented Mar 24, 2026

GET requests carry their GraphQL operation in query parameters, not a body, so there is no legitimate reason to send any Content-Type other than application/json (which Apollo Client Web sends by default). Reject any other value — including valid MIME types like text/plain and application/graphql, as well as malformed values — with HTTP 415.

This also addresses GHSA-9q82-xgwf-vj6h

Summary by CodeRabbit

  • Security

    • GET requests with a Content-Type other than application/json are now rejected (HTTP 415).
    • GET requests without a Content-Type remain allowed but may require an operation-name or preflight header when default CSRF prevention is enabled.
    • Users relying on cookies or HTTP Basic Auth should upgrade to v5.5.0.
  • Documentation

    • Clarified request handling and CSRF-prevention guidance in docs.

GET requests carry their GraphQL operation in query parameters, not a
body, so there is no legitimate reason to send any Content-Type other
than application/json (which Apollo Client Web sends by default). Reject
any other value — including valid MIME types like text/plain and
application/graphql, as well as malformed values — with HTTP 415.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@glasser glasser requested a review from carodewig March 24, 2026 19:33
@glasser glasser requested a review from a team as a code owner March 24, 2026 19:33
@apollo-librarian
Copy link
Copy Markdown

apollo-librarian bot commented Mar 24, 2026

✅ Docs preview ready

The preview is ready to be viewed. View the preview

File Changes

0 new, 3 changed, 0 removed
* (developer-tools)/apollo-server/(latest)/integrations/building-integrations.md
* (developer-tools)/apollo-server/(latest)/security/cors.mdx
* (developer-tools)/apollo-server/(latest)/workflow/requests.md

Build ID: fee45bd747a958a117a72c9e
Build Logs: View logs

URL: https://www.apollographql.com/docs/deploy-preview/fee45bd747a958a117a72c9e


⚠️ AI Style Review — 1 Issue Found

Summary

This pull request updates the documentation to align with several style guide standards. Key changes include adopting reader-centric framing for Apollo Client Web, simplifying language by removing unnecessary emphasis and wordiness, and ensuring Apollo Server is used as a proper noun without leading articles. Structural improvements were made to list items to enhance scannability by moving excessive detail to body text. Formatting updates include using plain text for version numbers and maintaining consistent present tense for system behaviors. Finally, the voice was refined to be more prescriptive, focusing on the recommended 'happy path' for headers and client usage.

Duration: 2658ms
Review Log: View detailed log

This review is AI-generated. Please use common sense when accepting these suggestions, as they may not always be accurate or appropriate for your specific context.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2dbb1be0-baa9-4dd9-8de2-e24664e332a1

📥 Commits

Reviewing files that changed from the base of the PR and between 83c5926 and 32a2e12.

📒 Files selected for processing (1)
  • docs/source/security/cors.mdx

📝 Walkthrough

Walkthrough

A security-hardening update in v5.5.0 enforces Content-Type validation: GET requests with a present Content-Type other than application/json are rejected with HTTP 415; docs and tests updated to reflect the new behavior.

Changes

Cohort / File(s) Summary
Changeset
.changeset/chatty-worlds-vanish.md
Adds a changeset describing the v5.5.0 security behavior: GET with non-application/json Content-Type is rejected (HTTP 415); GET without Content-Type remains allowed under CSRF header conditions.
Documentation
docs/source/integrations/building-integrations.md, docs/source/security/cors.mdx, docs/source/workflow/requests.md
Clarifies CSRF-prevention assumptions and Content-Type rules for GET/POST requests, documents that only application/json (with optional parameters) is permitted for GET when Content-Type is present.
Test Suite Updates
packages/integration-testsuite/src/apolloServerTests.ts, packages/integration-testsuite/src/httpServerTests.ts
Adjusts existing CSRF tests to expect HTTP 415 for invalid Content-Type on GET; adds tests rejecting text/plain, application/graphql, malformed types, and accepting application/json (with charset).
Implementation
packages/server/src/runHttpQuery.ts
Adds GET request Content-Type parsing via whatwg-mimetype and immediate rejection (BadRequestError with 415) when the essence is not application/json.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately reflects the primary change: rejecting GET requests with Content-Type headers other than application/json, which is the core feature implemented across all modified files.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch get-content-type-validation

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.

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci bot commented Mar 24, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Copy link
Copy Markdown

@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 (2)
.changeset/chatty-worlds-vanish.md (1)

12-12: Consider making this sentence evergreen.

Line 12’s “as of March 2026” timestamp may become stale quickly in long-lived release notes.

📝 Suggested wording
- Apollo is aware of one browser which as of March 2026 has a bug which allows an attacker to circumvent Apollo Server's CSRF prevention feature to carry out read-only XS-Search-style CSRF attacks.
+ Apollo is aware of a browser bug that allows an attacker to circumvent Apollo Server's CSRF prevention feature to carry out read-only XS-Search-style CSRF attacks.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/chatty-worlds-vanish.md at line 12, The phrase "as of March 2026"
makes the release note line time-sensitive; update the sentence in the
.changeset entry that currently reads "as of March 2026" to an evergreen form
(e.g., remove the date or replace with "recently" or "currently being patched by
the vendor") so it does not become stale—edit the sentence mentioning the
browser bug and Apollo Server v5.5.0 to omit the explicit timestamp while
preserving the meaning about the vendor patch and mitigation.
packages/integration-testsuite/src/httpServerTests.ts (1)

630-634: Rename this test for accuracy.

Line 630 says “non-preflighted”, but the case uses application/graphql, which is preflighted (as your own comment in Lines 631-633 notes).

🧹 Suggested rename
-it('throws an error if GET request has a non-preflighted non-application/json content-type', async () => {
+it('throws an error if GET request has a preflighted non-application/json content-type', async () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/integration-testsuite/src/httpServerTests.ts` around lines 630 -
634, The test description is inaccurate: update the it(...) string that
currently reads "throws an error if GET request has a non-preflighted
non-application/json content-type" to reflect that the case uses a preflighted
MIME type (application/graphql). Locate the it(...) block (the test wrapping
createApp()) and change the description to something like "throws an error if
GET request has a preflighted non-application/json content-type" or more
specific "throws an error if GET request has a preflighted application/graphql
content-type".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/source/security/cors.mdx`:
- Line 203: Fix the grammar in the summary sentence that currently reads "the
incoming request include" by changing "include" to "includes"; locate the
sentence in the paragraph discussing Content-Type (the sentence starting "This
means that all `POST` requests...") and update it so it reads "the incoming
request includes a `Content-Type` header specifying `application/json`" to
correct subject-verb agreement.

---

Nitpick comments:
In @.changeset/chatty-worlds-vanish.md:
- Line 12: The phrase "as of March 2026" makes the release note line
time-sensitive; update the sentence in the .changeset entry that currently reads
"as of March 2026" to an evergreen form (e.g., remove the date or replace with
"recently" or "currently being patched by the vendor") so it does not become
stale—edit the sentence mentioning the browser bug and Apollo Server v5.5.0 to
omit the explicit timestamp while preserving the meaning about the vendor patch
and mitigation.

In `@packages/integration-testsuite/src/httpServerTests.ts`:
- Around line 630-634: The test description is inaccurate: update the it(...)
string that currently reads "throws an error if GET request has a
non-preflighted non-application/json content-type" to reflect that the case uses
a preflighted MIME type (application/graphql). Locate the it(...) block (the
test wrapping createApp()) and change the description to something like "throws
an error if GET request has a preflighted non-application/json content-type" or
more specific "throws an error if GET request has a preflighted
application/graphql content-type".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e713a20b-f102-4044-b593-9c54b849cfbd

📥 Commits

Reviewing files that changed from the base of the PR and between e66bd0b and 83c5926.

📒 Files selected for processing (7)
  • .changeset/chatty-worlds-vanish.md
  • docs/source/integrations/building-integrations.md
  • docs/source/security/cors.mdx
  • docs/source/workflow/requests.md
  • packages/integration-testsuite/src/apolloServerTests.ts
  • packages/integration-testsuite/src/httpServerTests.ts
  • packages/server/src/runHttpQuery.ts
📜 Review details
🧰 Additional context used
🪛 GitHub Check: AI Style Review
docs/source/security/cors.mdx

[notice] 203-203: docs/source/security/cors.mdx#L203
Framing: Use the imperative 'ensure' to make the summary more direct and reader-centric.

Language: Corrected 'include' to 'includes' to ensure proper grammar.

Products and Features: Remove 'the' before 'Apollo Server' as it is not part of the proper product name.

Structural Elements: Keep list items short for scannability. Move the detailed explanation and parenthetical notes to the following paragraph.

Text Formatting: Use code font for the GET keyword and use plain text for version numbers (v5.5.0).

Verb Tense and Voice: Use present tense instead of future tense and active voice instead of passive voice where possible.

Voice: The original text is unopinionated and overly verbose. Prescribe the 'happy path' of using application/json and Apollo Client directly.

Word and Symbol Usage: Avoid using 'do' for emphasis in 'do include'; it's more direct to say 'include'.

- The incoming request includes a `Content-Type` header that specifies a type other than `text/plain`, `application/x-www-form-urlencoded`, or `multipart/form-data`. Notably, a `Content-Type` of `application/json` (including any suffix like `application/json; charset=utf-8`) is sufficient. This means that all `POST` requests (which must use `Content-Type: application/json`) will be executed. Additionally, all versions of [Apollo Client Web](/react/api/link/apollo-link-http) that support `GET` requests include `Content-Type: application/json` headers, so any request from Apollo Client Web (`POST` or `GET`) will be executed. (As of v5.5.0, Apollo Server rejects GET requests which contain a non-empty `Content-Type` other than `application/json`, so in practice this bullet point could be summarized as "ensure the incoming request includes a `Content-Type` header specifying `application/json`".)
🪛 markdownlint-cli2 (0.21.0)
docs/source/integrations/building-integrations.md

[warning] 124-124: Emphasis style
Expected: underscore; Actual: asterisk

(MD049, emphasis-style)


[warning] 124-124: Emphasis style
Expected: underscore; Actual: asterisk

(MD049, emphasis-style)

🔇 Additional comments (5)
packages/server/src/runHttpQuery.ts (2)

24-24: New MIME parsing import is appropriate.

Line 24 cleanly introduces the parser dependency needed for stricter GET header validation.


199-211: GET content-type validation is correctly enforced early.

The new guard in Lines 199-211 rejects invalid/malformed GET content-type with 415 before request construction, which matches the security objective.

docs/source/workflow/requests.md (1)

85-87: Docs update is clear and aligned with runtime behavior.

Lines 85-87 accurately describe allowed GET content-type values and the 415 rejection path.

docs/source/integrations/building-integrations.md (1)

123-124: Security guidance here is strong and actionable.

Lines 123-124 clearly communicate the CSRF risk when integrations accept unsafe POST content-types.

packages/integration-testsuite/src/apolloServerTests.ts (1)

3180-3194: Test expectations now correctly match the new GET validation path.

The updated assertions in Lines 3180-3194 validate both HTTP 415 and invalidRequestWasReceived error propagation.

@glasser glasser merged commit ada1200 into main Mar 24, 2026
19 of 20 checks passed
@glasser glasser deleted the get-content-type-validation branch March 24, 2026 19:41
@github-actions github-actions bot mentioned this pull request Mar 24, 2026
glasser added a commit that referenced this pull request Mar 24, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @apollo/server-integration-testsuite@5.5.0

### Minor Changes

- [#8191](#8191)
[`ada1200`](ada1200)
Thanks [@glasser](https://github.com/glasser)! - ⚠️ SECURITY
`@apollo/server/standalone`:

Apollo Server now rejects GraphQL `GET` requests which contain a
`Content-Type` header other than `application/json` (with optional
parameters such as `; charset=utf-8`). Any other value is now rejected
with a 415 status code.

(GraphQL `GET` requests without a `Content-Type` header are still
allowed, though they do still need to contain a non-empty
`X-Apollo-Operation-Name` or `Apollo-Require-Preflight` header to be
processed if the default CSRF prevention feature is enabled.)

This improvement makes Apollo Server's CSRF more resistant to browsers
which implement CORS in non-spec-compliant ways. Apollo is aware of one
browser which as of March 2026 has a bug which allows an attacker to
circumvent Apollo Server's CSRF prevention feature to carry out
read-only XS-Search-style CSRF attacks. The browser vendor is in the
process of patching this vulnerability; upgrading Apollo Server to
v5.5.0 mitigates this vulnerability.

**If your server uses cookies (or HTTP Basic Auth) for authentication,
Apollo encourages you to upgrade to v5.5.0.**

This is technically a backwards-incompatible change. Apollo is not aware
of any GraphQL clients which provide non-empty `Content-Type` headers
with `GET` requests with types other than `application/json`. If your
use case requires such requests, please [file an
issue](https://github.com/apollographql/apollo-server/issues) and we may
add more configurability in a follow-up release.

See [advisory
GHSA-9q82-xgwf-vj6h](GHSA-9q82-xgwf-vj6h)
for more details.

### Patch Changes

- Updated dependencies
\[[`ada1200`](ada1200)]:
    -   @apollo/server@5.5.0

## @apollo/server@5.5.0

### Minor Changes

- [#8191](#8191)
[`ada1200`](ada1200)
Thanks [@glasser](https://github.com/glasser)! - ⚠️ SECURITY
`@apollo/server/standalone`:

Apollo Server now rejects GraphQL `GET` requests which contain a
`Content-Type` header other than `application/json` (with optional
parameters such as `; charset=utf-8`). Any other value is now rejected
with a 415 status code.

(GraphQL `GET` requests without a `Content-Type` header are still
allowed, though they do still need to contain a non-empty
`X-Apollo-Operation-Name` or `Apollo-Require-Preflight` header to be
processed if the default CSRF prevention feature is enabled.)

This improvement makes Apollo Server's CSRF more resistant to browsers
which implement CORS in non-spec-compliant ways. Apollo is aware of one
browser which as of March 2026 has a bug which allows an attacker to
circumvent Apollo Server's CSRF prevention feature to carry out
read-only XS-Search-style CSRF attacks. The browser vendor is in the
process of patching this vulnerability; upgrading Apollo Server to
v5.5.0 mitigates this vulnerability.

**If your server uses cookies (or HTTP Basic Auth) for authentication,
Apollo encourages you to upgrade to v5.5.0.**

This is technically a backwards-incompatible change. Apollo is not aware
of any GraphQL clients which provide non-empty `Content-Type` headers
with `GET` requests with types other than `application/json`. If your
use case requires such requests, please [file an
issue](https://github.com/apollographql/apollo-server/issues) and we may
add more configurability in a follow-up release.

See [advisory
GHSA-9q82-xgwf-vj6h](GHSA-9q82-xgwf-vj6h)
for more details.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: David Glasser <glasser@apollographql.com>
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