Skip to content

fix(accounts-base): gate /_accounts/cookie/* endpoints behind useHttpOnlyCookies and cap /set body size - #14657

Open
italojs wants to merge 2 commits into
develfrom
fix/issue-14654-gate-cookie-endpoints
Open

fix(accounts-base): gate /_accounts/cookie/* endpoints behind useHttpOnlyCookies and cap /set body size#14657
italojs wants to merge 2 commits into
develfrom
fix/issue-14654-gate-cookie-endpoints

Conversation

@italojs

@italojs italojs commented Aug 10, 2026

Copy link
Copy Markdown
Member

Fixes #14654

Since accounts-base 3.3.0 (Meteor 3.5), the HttpOnly cookie endpoints — POST /_accounts/cookie/set, GET /_accounts/cookie/refresh, POST /_accounts/cookie/clear — are mounted on every server, even when the app never enabled useHttpOnlyCookies. /set also buffered the entire request body in memory before validating it.

Changes

  • The handlers now fall through (next()) unless the feature is enabled, so by default the routes behave as if they were never mounted. Both documented opt-ins count: Accounts.config({ useHttpOnlyCookies: true }) on the server and Meteor.settings.public.packages.accounts.useHttpOnlyCookies. The check runs per request because Accounts.config usually runs in Meteor.startup, after the handlers are registered.
  • The /set body is now capped at 4 KB — rejected via Content-Length up front and enforced while streaming — returning 413 {"error":"body_too_large"}.

Note: enabling the feature only on the client used to work by accident (the endpoints were always live). It now requires the documented server-side opt-in.

Verification

Repro: https://github.com/italojs/meteor-issue-repros/tree/issue-14654 (stock 3.5.1 minimal app + accounts-base)

  • Before: all three endpoints answer even though the app never opted in, and a 5 MB POST to /set is fully buffered before the 400.
  • After: with the feature off, the requests fall through to the app's own routing; with it on, the endpoints behave exactly as before; bodies over 4 KB get a 413, answered mid-upload.
  • All 20 server-side accounts cookie tinytests pass, including 3 new ones (413 via streaming, 413 via Content-Length, fall-through when disabled). Two client-side DDP login tests failed with the rate limiter's too-many-requests — a login-flow flake unrelated to these HTTP handlers.

Summary by CodeRabbit

  • New Features

    • Added opt-in support for HTTP-only cookie handling through account settings.
    • Added protection against oversized cookie request payloads, returning a clear error when the limit is exceeded.
  • Bug Fixes

    • Improved handling of multibyte request content when enforcing payload limits.
    • Cookie refresh and clear requests now correctly pass through when the feature is disabled.

… cap /set body size (#14654)

The HttpOnly cookie endpoints (set/refresh/clear) were mounted
unconditionally at package load, exposing three unauthenticated HTTP
paths on every Meteor 3.5+ server even when the app never enabled
useHttpOnlyCookies. The /set endpoint also buffered the entire request
body in memory before validating it.

Handlers now fall through to the app's own routing unless the feature
is enabled — via Accounts.config({ useHttpOnlyCookies: true }) on the
server or Meteor.settings.public.packages.accounts.useHttpOnlyCookies.
The check happens per request because Accounts.config typically runs
inside Meteor.startup, after the handlers are registered.

readJson now rejects bodies larger than 4 KB (checked against
Content-Length up front and enforced while streaming), returning 413.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for v3-meteor-api-docs canceled.

Name Link
🔨 Latest commit dcb722f
🔍 Latest deploy log https://app.netlify.com/projects/v3-meteor-api-docs/deploys/6a7a150de6d47f0008ba1c35

@netlify

netlify Bot commented Aug 10, 2026

Copy link
Copy Markdown

Deploy Preview for v3-migration-docs canceled.

Name Link
🔨 Latest commit dcb722f
🔍 Latest deploy log https://app.netlify.com/projects/v3-migration-docs/deploys/6a7a150d75a05300085ef2cf

italojs added a commit to italojs/meteor-issue-repros that referenced this pull request Aug 10, 2026
italojs added a commit to italojs/meteor-issue-repros that referenced this pull request Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d1c4b3f-2858-4f89-9982-40dec8a1a2d2

📥 Commits

Reviewing files that changed from the base of the PR and between f8f280d and dcb722f.

📒 Files selected for processing (2)
  • packages/accounts-base/accounts_cookie_server_tests.js
  • packages/accounts-base/server_http_cookies.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/accounts-base/accounts_cookie_server_tests.js
  • packages/accounts-base/server_http_cookies.js

📝 Walkthrough

Walkthrough

The HTTP-only cookie endpoints now use opt-in configuration gating. /set rejects JSON bodies larger than 4 KB with 413 body_too_large, including oversized streamed and declared requests. Tests cover enabled and disabled endpoint behavior.

Changes

HTTP-only cookie controls

Layer / File(s) Summary
Request parsing and endpoint enforcement
packages/accounts-base/server_http_cookies.js
The server checks HTTP-only cookie configuration, limits JSON bodies to 4 KB by UTF-8 byte length, and bypasses the set, refresh, and clear handlers when disabled.
Cookie endpoint behavior tests
packages/accounts-base/accounts_cookie_server_tests.js
Tests enable HTTP-only cookies, verify oversized-body responses, verify UTF-8 byte enforcement, and verify endpoint fall-through with configuration restoration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: nachocodoner, henriquealbert, grubba27

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the endpoint gating and /set request-body limit, which are the primary changes.
Linked Issues check ✅ Passed The changes satisfy issue #14654 by gating all three endpoints and enforcing a 4 KB /set body limit.
Out of Scope Changes check ✅ Passed The changes and tests remain focused on the endpoint gating and /set request-body limit described in issue #14654.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-14654-gate-cookie-endpoints

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@packages/accounts-base/accounts_cookie_server_tests.js`:
- Around line 228-229: Update the assertion for refreshRes in the
disabled-refresh test to require the specific status returned by the downstream
unhandled-route handler, rather than merely checking that it is not 204.
Preserve the existing GET request through REFRESH_PATH and use the test app’s
known fall-through status.

In `@packages/accounts-base/server_http_cookies.js`:
- Around line 75-82: Update the request-size check in the data handler around
req.setEncoding and MAX_JSON_BODY_BYTES to measure the accumulated body’s UTF-8
byte length rather than JavaScript string length. Preserve the existing pause,
reset, and settle behavior when the byte limit is exceeded.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cf8430fc-f0e4-47f9-af68-d17bdf3071f0

📥 Commits

Reviewing files that changed from the base of the PR and between 5076d2f and f8f280d.

📒 Files selected for processing (2)
  • packages/accounts-base/accounts_cookie_server_tests.js
  • packages/accounts-base/server_http_cookies.js

Comment thread packages/accounts-base/accounts_cookie_server_tests.js
Comment thread packages/accounts-base/server_http_cookies.js Outdated
@italojs italojs added this to the Release 3.5.2 milestone Aug 10, 2026
… test

String.length counts UTF-16 code units, so a body of multi-byte
characters could exceed the 4 KB limit while passing the check.
readJson now accumulates raw buffers and counts actual bytes.

The disabled-endpoints test now also asserts the refresh response is
not application/json, proving the request fell through to the app
stack instead of merely not being a 204.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.

accounts-base: server always mounts /_accounts/cookie/* endpoints even when useHttpOnlyCookies is disabled; unbounded request body on /set

1 participant