fix(web): bound metered /api route inputs (OG size cap, Exa url caps, research guards) - #1580
Closed
Sravanjangam wants to merge 1 commit into
Closed
fix(web): bound metered /api route inputs (OG size cap, Exa url caps, research guards)#1580Sravanjangam wants to merge 1 commit into
Sravanjangam wants to merge 1 commit into
Conversation
- /api/og: stream-read fetched HTML with a 2MB cap (Content-Length pre-check + incremental abort) instead of buffering response.text() unbounded; returns 413 when exceeded. Applies to the redirect path too. - /api/onboarding/extract-content: cap urls at 10 per request, each <=2048 chars and http(s)-only, so the endpoint can't relay arbitrary unbounded URL lists into paid Exa quota. - /api/onboarding/research: bound name (<=200) and email (<=320) before prompt interpolation and add a 60s abort signal on generateText so a hung tool call can't burn xAI credits indefinitely.
graphite-app Bot
pushed a commit
that referenced
this pull request
Aug 23, 2026
Cherry-picks #1579 and #1580 from @Sravanjangam (security audit #1578), plus improvements on top. - `/api/og`, `/api/onboarding/extract-content` and `/api/onboarding/research` now verify the session against the auth backend; the middleware only checked that a cookie was present, so a forged cookie reached handlers that spend metered Exa/xAI quota. - Bounds those routes: 2MB cap on fetched HTML, max 10 http(s) URLs per request, name/email length limits and a 60s timeout on the LLM call. - De-duplicates URLs before calling Exa, and collapses whitespace in `name`/`email` so a newline can't forge extra prompt lines. Both adapted from @SEPURI-SAI-KRISHNA's #1528 and #1530. - Deletes the unused, unauthenticated `account-status` route. Verified locally: pre-fix `/api/og` returned 200 for a forged cookie, post-fix it returns 401. Five duplicate URLs collapse to two before reaching Exa, and a newline-laden `name` arrives as a single prompt line. Supersedes #1528 and #1530.
Member
|
Merged as part of #1589, which cherry-picks your commit with your authorship intact. Changes we made on top: URLs are now parsed with Thanks @Sravanjangam. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi supermemory team 👋 Thanks for building such a great product! While running a security & quality audit of the repo we hit this issue and put together a small, tested fix — details below.
Problem
Three metered routes accepted unbounded attacker-controlled input:
app/api/og/route.tsbuffered entire fetched HTML into memory viaresponse.text()— size chosen by the fetched origin — then cached it publicly.app/api/onboarding/extract-content/route.tsrelayed an arbitrary-length array of arbitrary URLs into paid Exa quota.app/api/onboarding/research/route.tsinterpolated uncappedname/emailstrings into the LLM prompt with no timeout on thegenerateTextcall.Anonymous callers (see #1579/H1) could exhaust worker memory or drain third-party credits. Part of #1578 (findings M1–M3).
Solution
Hard caps enforced at the trust boundary with explicit early status codes — reject instead of truncating mid-operation.
Changes
og/route.ts→readBoundedText(): streamed read capped at 2 MB +Content-Lengthprecheck, both fetch paths →413extract-content/route.ts→ ≤10 URLs,http(s)only vianew URL(), ≤2048 chars each →400research/route.ts→name≤200,email≤320 chars +AbortSignal.timeout(60_000)Verification
Fresh from the committed branch: web unit suites green;
tsc --noEmitadds zero new errors vs baseline for all touched files; Biome clean. Merge note: depends on #1579's guards landing first (same files).Happy to iterate on any of this — feedback and reworks very welcome! 🙏
Environment
fix/metered-api-input-caps— all gates re-run fresh at commit2fb7a5c91b61