generation browser proxy CSRF: protect cookie-authenticated submission routes
·
A browser-facing proxy may use a session cookie while its backend uses a Genace bearer key. Those are two different authentication mechanisms. Keeping the upstream key private is necessary, but it does not by itself protect your cookie-authenticated spending endpoint from cross-site request forgery. Apply the defenses appropriate to your framework and application origin.
Identify state-changing application actions
Submission creates work, cancellation changes an operation, and publication can expose an asset. Protect those routes under your application’s session and permission policy. Do not place a creation action behind GET simply because a hyperlink is easier to trigger.
Use your framework’s maintained CSRF mechanism when available. Depending on the design, that may include a session-bound token and verification of the request origin. Cookie attributes and Fetch Metadata checks can add defense, but no isolated header check should be advertised as a universal replacement for the framework’s complete policy.
export function sameApplicationOrigin(request, expectedOrigin) {
const origin = request.headers.get('origin');
if (!origin) return false;
try {
const parsed = new URL(origin);
return ['http:', 'https:'].includes(parsed.protocol) &&
origin === parsed.origin && origin === expectedOrigin;
} catch {
return false;
}
}
This is only an origin-check building block for a browser route. It is not a complete CSRF implementation and intentionally rejects missing Origin under a strict policy. If non-browser clients require the same business operation, give them an explicitly reviewed authentication path instead of weakening browser checks ad hoc.
The Origin header contains a scheme, host, and optional port, or the opaque value null. It is not an arbitrary page URL. URL parsing alone can discard a path, credentials, query, or fragment; it can also extract an embedded origin from a blob URL. Comparing only that parsed origin would accept input outside this helper’s intended policy.
This deliberately narrow check accepts one canonical HTTP(S) origin. It rejects null, origin lists, URL components, and noncanonical spellings, including an explicit default port or uppercase hostname that the URL serializer would remove or normalize. Those equivalent spellings are policy rejections, not evidence of an attack. Configure expectedOrigin as an exact serialized origin without a trailing slash; validate configuration at startup. HTTP development origins are accepted only when explicitly configured. Do not normalize arbitrary request URLs into trusted header values before this check.
Derive the expected origin from trusted configuration
Do not trust an arbitrary Host or forwarded-host value as the authority for deciding whether the caller’s origin is allowed. Configure the application origin and understand which proxy headers your deployment validates. Review development origins separately rather than allowing wildcard matching in production.
Require the intended content type and request shape, but do not assume JSON alone resolves every browser boundary. CORS controls what browsers may read and send under its rules; it is not a substitute for authenticating and authorizing each state-changing request.
Keep upstream credentials outside the browser flow
After local checks pass, build the generation request in server code with the private bearer key. Map the accepted job_id to the authorized local operation and tenant. A status or SSE relay should load that mapping rather than accepting any remote job ID the browser provides.
If the browser navigates away, stopping the request does not establish cancellation. Preserve known IDs and uncertain submission states so request lifecycle events cannot bypass your operation ledger or trigger replacement renders.
Verify rejected requests have no side effects
Test an allowed origin with a valid session and CSRF token, a cross-site origin, missing token, missing Origin, and malformed URL-like values. Include credentials, path/query/fragment, blob, null, lookalike hosts, different ports, and a Host or forwarded-host header that attempts to influence the decision. Helper tests do not prove browser exploitability or integration: test your actual route with a mocked upstream client and assert rejected requests never submit. Test cancellation and publication too, not only image creation.
Confirm error responses do not disclose the server key or another tenant’s operation. Review browser and non-browser authentication paths as separate contracts, and document any deliberate exceptions with their owner and tests.
See tenant authorization, server-side keys, and aborted requests.
Continue with security
Where these facts come from
- Editorial keyword hypothesis; search volume not measured
- https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Origin
- codebase: src/ai/api/auth.ts