Repository navigation
fix(auth): rate-limit socket tokens per user, with an IP backstop - #8958
Conversation
… backstop The 30/min budget was keyed on client IP and checked before the session, so an office behind one NAT address (or every tab reconnecting after a deploy) shared a single budget and throttled each other. The same 30 burst / 30 per minute now applies per session user, after a cookie-cached session read; the mint still re-reads the session from the database. A 300/min IP backstop stays in front of everything so unauthenticated traffic is rejected before any session lookup. 401 and 429 + Retry-After responses are unchanged.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
1 issue found across 4 files
Confidence score: 4/5
- In
apps/sim/app/api/auth/socket-token/route.ts, stale-cookie requests hit the session DB before the per-user limit, and the 300/min IP backstop allows 10× more reads than the old cap. Apply a tighter IP limit beforegetSession().
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/sim/app/api/auth/socket-token/route.ts">
<violation number="1" location="apps/sim/app/api/auth/socket-token/route.ts:52">
P2: The per-user limit runs after `getSession()`, so stale-cookie requests reach the session DB before any per-user budget applies. Only the 300/min IP backstop bounds those reads, which is 10x the old 30/min per-IP cap. Consider lowering the backstop or confirming this trade-off is intended.</violation>
</file>
Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.
Turn on auto-fix | Re-trigger cubic
|
…oth budgets in tests
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 4 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.
Turn on auto-fix | Re-trigger cubic
--diagnostics read an empty or truncated diagnostics.txt as fewer errors, so a failed compile's artifact plus --update could erase the baseline. --report now writes status.json (exit code and printed error count) once the compile's output and exit code agree, and --diagnostics requires it: exit 0 must mean no errors, the parse must match the recorded count, and a missing or malformed status fails. Command-level tests cover each case and that --update never writes the baseline from such input. Also passes a route context to the socket-token route test's POST call, the one new test type error (TS2554) the ratchet caught after #8958.
* ci: ratchet type errors in apps/sim unit tests per file
apps/sim's tsconfig excludes *.test.ts(x), so ~3.4k test files are never
type-checked and any new test can add errors. check:test-types runs the
native tsc on apps/sim/tsconfig.tests.json (the app config with tests left
in), counts errors per file, and compares with a shrink-only baseline,
matching check:explicit-any's semantics: a rise or a new file fails, a drop
fails until --update shrinks it, --update never raises, --update --init only
creates a missing baseline. Output it cannot place (global diagnostics, a
crash) fails outright instead of reading as fewer errors.
It type-checks the whole app, so it runs in its own test-types job gated
like test (wired into ci-gate.sh), not in check:audits. On failure the job
uploads counts.json and the compiler output; --counts <file> lets the
baseline be bootstrapped or shrunk from that artifact without a local
compile.
* ci: commit the test type-error baseline from CI and drop the one-time --init path
Baseline from run 38342772080's test-types counts: 3209 errors in 874 files.
--update stays shrink-only; a missing baseline is restored from git.
* ci: ratchet test type errors per file and TS code, with command-level tests
A per-file count let one new error replace a fixed one with the total flat.
The baseline is now { file: { TSnnnn: count } }: any (file, code) count
that rises fails, including a new code in a baselined file, and --update
stays shrink-only per pair. The key stops at the code: line and column
move with edits, and messages print types that change with unrelated
source or compiler versions.
--diagnostics <file> replaces --counts: it reads a saved compiler output
(the CI artifact's diagnostics.txt) through the same parser and undercount
checks, so a fix can shrink the baseline without a local compile. The
baseline was migrated from run 38342772080's diagnostics.txt with the
script's parser: 3209 errors in 874 files across 52 codes, every per-file
total equal to the previous baseline's.
Command-level tests run the real script on fixture diagnostics: unchanged,
a rising count, a new code replacing a fixed error, a new file, a dropped
count, --update refusing a raise, --update shrinking, and unparseable or
inconsistent output. The checks.yml comment now describes the artifact as
input for shrinking the existing baseline.
* ci: verify saved test-type diagnostics against the compile's exit status
--diagnostics read an empty or truncated diagnostics.txt as fewer errors,
so a failed compile's artifact plus --update could erase the baseline.
--report now writes status.json (exit code and printed error count) once
the compile's output and exit code agree, and --diagnostics requires it:
exit 0 must mean no errors, the parse must match the recorded count, and
a missing or malformed status fails. Command-level tests cover each case
and that --update never writes the baseline from such input.
Also passes a route context to the socket-token route test's POST call,
the one new test type error (TS2554) the ratchet caught after #8958.
* ci: read the saved compiler status through toRecord
Summary
/api/auth/socket-tokenallowed 30 mints per minute per client IP, checked before the session. The client mints one token per page load or reconnect. So an office behind one NAT IP, or every tab reconnecting after a deploy, shared a single 30/min budget, and some users were left waiting on a 429. Meanwhile one user rotating IPs could get past the limit entirely.New order:
getSession()to read the user id. No user means 401 with the same body as before.enforceUserRateLimit('socket-token', userId), 30 burst / 30 per min. No user gets less than the old per-IP budget, and rotating IPs no longer helps.generateOneTimeTokenre-validates the session against the database, bypassing the cookie cache, and fails closed with 401.Both 429s carry
Retry-After, which the client honors (#8952). Session cookies are signed with the auth secret, so a client can't target another user's budget. If the limiter's store is unavailable, behavior is the same as before. This is stricter than the precedent elsewhere in the repo:cli/auth/approveandlink-previewlimit per user only, with no IP backstop.Test plan
route.test.ts, using the real limiter with in-memory storage. All 3 cases fail on the old route:check:test-patterns