API security headers
Driftstack's HTTP API sets a fixed, reviewable set of security headers on every response. This page documents what they are and why, so security reviewers don't have to derive it from a production capture.
Always-on transport headers
| Header | Value | Why |
|---|---|---|
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | 2-year HSTS, eligible for the browser preload list. Closes first-visit downgrade attacks before TLS upgrade kicks in. |
X-Content-Type-Options | nosniff | Browsers must not infer MIME types from content. |
X-Frame-Options | SAMEORIGIN | Driftstack ships no embeddable UI; framing is disallowed by default. |
Referrer-Policy | no-referrer | No referrer leakage to third parties. |
X-DNS-Prefetch-Control | off | Disables speculative DNS for embedded URLs. |
Cache-Control posture
| Path | Cache-Control |
|---|---|
/v1/* (caller-private default) | no-store, private |
/v1/agent-sessions/{id}/transcript (authenticated SSE) | no-cache, no-store, private, no-transform |
/v1/status, /v1/status/incidents,
/v1/status/incidents/{id}, and
/v1/status/sla (public JSON)
| public, max-age=30 |
/v1/status/stream (SSE) | no-cache, no-transform |
Caller-private /v1/* responses default to
no-store, private. The authenticated transcript stream
listed above adds no-cache and no-transform
while retaining no-store, private; it also reflects only an
allowed Origin and sends Vary: Origin. This is
defense-in-depth so shared / proxy caches can't hold onto private
payloads and browser back-forward cache can't serve stale state
after logout. Public status reads opt into the public policies
shown above.
CORS
The API uses an explicit allow-list of origins; SDK consumers
can call from any origin because the SDK ships
Authorization: Bearer … and never relies on
browser-cookie auth. Pre-flight responses cache for 10 minutes.
credentials: true stays on for the browser clients,
but no route reads a cookie: signed-in calls, the dashboard's
included, send Authorization: Bearer …; the two live
event streams, which a browser cannot give a header, take the same
token as a ds_token query parameter.
Access-Control-Allow-Origin: <reflected allow-list match>
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: authorization, content-type, x-request-id, stripe-signature, x-nowpayments-sig, idempotency-key, x-byok-anthropic-api-key, x-driftstack-account, x-driftstack-gui-control-key, x-driftstack-conversation-token, x-driftstack-desktop-build, last-event-id
Access-Control-Expose-Headers: x-request-id, idempotent-replayed, x-ratelimit-bucket, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, ratelimit-limit, ratelimit-remaining, ratelimit-reset, retry-after
Access-Control-Max-Age: 600
Access-Control-Allow-Credentials: true Cross-Origin resource policy
Cross-Origin-Resource-Policy: cross-origin is set
explicitly. The default helmet value
(same-origin) would block legitimate SDK calls
from third-party origins because the CORS layer is our
boundary, not CORP.
What we don't set
- Content-Security-Policy. Driftstack serves no HTML — every endpoint returns JSON, plain text, CSV, or PDF. CSP would be a no-op.
- Cross-Origin-Embedder-Policy. Same logic — no embeddable surfaces.
- Cookie security flags. The API sets and reads no sign-in cookie: the REST API and the dashboard both authenticate with a bearer key.
Reporting a finding
Send disclosures to [email protected]. We do not publish a PGP key yet; if you would rather not send exploit details in plain text, email [email protected] first and we will arrange an encrypted channel. Our policy (no bug bounty; we credit researchers) is on the vulnerability-disclosure policy.