mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-26 17:02:32 +00:00
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.
47 lines
1.1 KiB
TypeScript
47 lines
1.1 KiB
TypeScript
import { getBackendUrl } from "./url-helpers"
|
|
|
|
const LOCAL_DEV_HOSTS = new Set(["localhost", "127.0.0.1", "::1"])
|
|
|
|
// `bun run dev:local` serves localhost while auth lives on api.supermemory.ai, so its cookie never arrives.
|
|
function isLocalDevRequest(request: Request): boolean {
|
|
if (process.env.NODE_ENV !== "development") {
|
|
return false
|
|
}
|
|
try {
|
|
return LOCAL_DEV_HOSTS.has(new URL(request.url).hostname)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// middleware.ts only checks the cookie is present; metered/proxy routes must verify it server-side.
|
|
export async function hasVerifiedSession(request: Request): Promise<boolean> {
|
|
if (isLocalDevRequest(request)) {
|
|
return true
|
|
}
|
|
|
|
const cookie = request.headers.get("cookie")
|
|
if (!cookie) {
|
|
return false
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${getBackendUrl()}/api/auth/get-session`, {
|
|
headers: { cookie },
|
|
redirect: "error",
|
|
cache: "no-store",
|
|
})
|
|
if (!response.ok) {
|
|
return false
|
|
}
|
|
const session: unknown = await response.json()
|
|
return Boolean(
|
|
session &&
|
|
typeof session === "object" &&
|
|
"user" in session &&
|
|
session.user,
|
|
)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|