Skip to content

fix(API): reject NUL bytes in query parameters instead of crashing with 500 - #8204

Open
bardock-2393 wants to merge 2 commits into
Flagsmith:mainfrom
bardock-2393:fix/nul-byte-query-params
Open

fix(API): reject NUL bytes in query parameters instead of crashing with 500#8204
bardock-2393 wants to merge 2 commits into
Flagsmith:mainfrom
bardock-2393:fix/nul-byte-query-params

Conversation

@bardock-2393

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Closes #2901

Several views (e.g. environments/identities/views.py's identifier lookup) pass a raw query parameter into a Postgres string query. When the value contains a NUL (0x00) byte, psycopg raises ValueError: A string literal cannot contain NUL (0x00) characters, which isn't caught anywhere and surfaces as an unhandled 500. The original report found 8 occurrences of this pattern across the codebase.

Rather than adding per-field serializer validation at each of the 8 call sites (and any future ones), this adds a small RejectNulByteQueryParamsMiddleware that checks request.GET for NUL bytes centrally and returns a 400 with a clear message before any view or the ORM ever sees the value — fixing all current and future call sites in one place.

How did you test this code?

Added unit tests for the middleware (test_unit_core_middleware_query_params.py), following the existing pattern used for NeverCacheMiddleware. Also manually verified end-to-end against a real APIClient request to the SDK identities endpoint with identifier=foo\x00bar: before the fix this would raise the reported ValueError; after the fix it returns 400 Bad Request with the message body instead. Ran tests/unit/core/ and the identities integration suite (67 tests) — all green, no regressions. make lint and make typecheck both clean.

…th 500

Any view that passes a query param straight into a Postgres string
query (e.g. environments/identities/views.py's identifier lookup)
raised an unhandled ValueError when the value contained a NUL byte,
since psycopg rejects NUL characters in string literals. Reject such
requests centrally in middleware instead of patching every call site
individually.
@bardock-2393
bardock-2393 requested a review from a team as a code owner August 1, 2026 18:21
@bardock-2393
bardock-2393 requested review from khvn26 and removed request for a team August 1, 2026 18:21
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

@bardock-2393 is attempting to deploy a commit to the Flagsmith Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6c046f62-73dc-4cee-aa16-972719b57c27

📥 Commits

Reviewing files that changed from the base of the PR and between 1a88f24 and 69cde38.

📒 Files selected for processing (3)
  • api/app/settings/common.py
  • api/core/middleware/query_params.py
  • api/tests/unit/core/middleware/test_unit_core_middleware_query_params.py

📝 Walkthrough

Walkthrough

The change adds RejectNulByteQueryParamsMiddleware. It returns HTTP 400 when a query parameter value contains a NUL character. It forwards valid requests to the configured response handler. The middleware is added to the Django middleware stack. Unit tests cover both request paths.

Estimated code review effort: 2 (Simple) | ~10 minutes

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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.

@github-actions github-actions Bot added the api Issue related to the REST API label Aug 1, 2026

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8dd6727b-1443-45a5-9d6e-8cae670e2b63

📥 Commits

Reviewing files that changed from the base of the PR and between fc33002 and 1a88f24.

📒 Files selected for processing (3)
  • api/app/settings/common.py
  • api/core/middleware/query_params.py
  • api/tests/unit/core/middleware/test_unit_core_middleware_query_params.py

Comment thread api/app/settings/common.py Outdated
Comment thread api/core/middleware/query_params.py
@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.57%. Comparing base (fc33002) to head (69cde38).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8204      +/-   ##
==========================================
- Coverage   98.71%   98.57%   -0.15%     
==========================================
  Files        1531     1533       +2     
  Lines       61263    61292      +29     
==========================================
- Hits        60475    60417      -58     
- Misses        788      875      +87     

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

- Run the middleware after CorsMiddleware so a short-circuited 400
  response still gets CORS headers, instead of the request bypassing
  CorsMiddleware entirely.
- Use QueryDict.lists() instead of .values(), which only yields the
  last value per key and let a NUL byte in an earlier value of a
  repeated query key slip through undetected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Null-terminated query parameters cause server errors in the Core SDK endpoints

1 participant