Headers reference

July 9, 2026 ยท View on GitHub

Last modified: 2026-07-09

Every header SBproxy reads or stamps, with the config that triggers it. This is the single source of truth; docs/manual.md and the marketing pages link here rather than duplicating the table inline.

The proxy touches headers in three places: request headers it reads from the client, response headers it emits back to the client, and headers it stamps on outbound requests it makes itself (webhooks, mirrors, shadow traffic, ledger calls). Each gets its own section below.

Request headers the proxy reads

These arrive on the inbound request. The proxy consumes them; most are also forwarded or stripped depending on trust.

HeaderDescriptionSource
X-Request-IdCorrelation ID. If present (and proxy.correlation_id.enabled, the default), its value is adopted as the request's correlation ID; otherwise the proxy mints a UUID v4. The header name is configurable via proxy.correlation_id.header.crates/sbproxy-core/src/server/request_phase.rs
x-sb-session-idCaller-supplied session ULID. Captured when it parses; invalid values are dropped and counted.crates/sbproxy-observe/src/capture.rs
x-sb-parent-session-idCaller-supplied parent session ULID for chaining agent sessions. Never auto-generated.crates/sbproxy-observe/src/capture.rs
x-sb-user-idCaller-supplied user identifier. First in the user-ID resolution order, ahead of the JWT sub claim and forward-auth headers.crates/sbproxy-observe/src/capture.rs
x-sb-property-*Per-request session properties captured onto the request event. Length-capped, allowlist-checked, and redacted per properties.redact.crates/sbproxy-observe/src/capture.rs
x-sb-flagsPer-request feature flags. x-sb-flags: debug turns on the debug response headers listed below and a DEBUG-level log line. Kill switch: --disable-sb-flags / SB_DISABLE_SB_FLAGS=1.crates/sbproxy-core/src/sb_flags.rs
x-sbproxy-tagCaller-supplied attribution tag read by the AI dispatch path.crates/sbproxy-core/src/server/ai_dispatch.rs
traceparent / tracestate / b3 / x-b3-*W3C Trace Context or B3 propagation. Parsed when present; a random trace context is generated otherwise.crates/sbproxy-core/src/server/request_phase.rs

TLS fingerprint sidecar headers

The x-sbproxy-tls-* family carries TLS fingerprints computed by a trusted TLS-terminating sidecar in front of the proxy. They are request headers, read only when the immediate TCP peer is in proxy.trusted_proxies, and stripped from untrusted peers so a client cannot forge its own fingerprint. They are never emitted on responses. Configuration lives under proxy.extensions.tls_fingerprint (the older features.tls_fingerprint block is migrated there by the config compiler), which also carries a sidecar_header_allowlist for alternate names such as x-forwarded-ja4.

HeaderDescription
x-sbproxy-tls-ja3JA3 client TLS fingerprint hash from the sidecar.
x-sbproxy-tls-ja4JA4 client TLS fingerprint hash from the sidecar.
x-sbproxy-tls-ja4hJA4H HTTP fingerprint. Sidecar-supplied, or computed by the proxy from the request when absent.
x-sbproxy-tls-ja4sJA4S server-side TLS fingerprint hash from the sidecar.
x-sbproxy-tls-trustworthySidecar's trust assertion. Overrides the proxy's own CIDR-based classification when present.

Response headers the proxy emits

Present by default

HeaderDescriptionSource
X-Request-IdThe correlation ID (adopted or minted) echoed to the client. On by default; disable with proxy.correlation_id.echo_response: false. The header name follows proxy.correlation_id.header.crates/sbproxy-core/src/server/proxy_http.rs
traceparentW3C Trace Context, echoed on the response. Generated when no inbound trace headers were present, otherwise derived from them. tracestate accompanies it when one exists.crates/sbproxy-core/src/server/proxy_http.rs

Conditional

These fire only when the relevant config or request state applies.

HeaderTriggerDescription
X-Sb-Session-IdA session ID was capturedEchoed when the caller supplied a valid ULID, or when the proxy auto-generated one. Auto-generation follows sessions.auto_generate: the default anonymous mints an ID only for requests with no resolved user identity; always and never do what they say. No session captured means no header.
x-sbproxy-cacheresponse_cache.enabled: true on the originValues: HIT, STALE, HIT-RESERVE. There is no MISS value; a cache miss simply omits the header.
x-sbproxy-debug-request-idRequest carried x-sb-flags: debugThe request's correlation ID, stamped for quick copy-paste debugging.
x-sbproxy-debug-config-revRequest carried x-sb-flags: debugThe compiled-config revision that served the request.
X-Sb-Property-<key>properties.echo: true on the originEach captured x-sb-property-* request property echoed back. Off by default.
x-sbproxy-idempotencyIdempotency middleware disengaged mid-requestSkip reason (oversize body, pool exhausted). Informational only.
x-sbproxy-retry-skip-reasonStatus-retry middleware skipped a retrySkip reason for dashboards.
Retry-After429 or a2a chain-depth denialOn rate-limit 429s this is opt-in via the policy's headers.include_retry_after (the built-in ddos and ai-crawl enforcers turn it on themselves). The a2a chain-depth-exceeded denial always sends Retry-After: 0, unconditionally.

Headers on outbound requests the proxy makes

These never appear on the client-facing response. A client curl will not see them.

Webhook and callback delivery

Stamped on event-sink, audit-log-sink, and callback deliveries (crates/sbproxy-core/src/server/callbacks.rs).

HeaderDescription
x-sbproxy-instanceStable identifier for the SBproxy instance that emitted the webhook.
x-sbproxy-config-revisionThe compiled-config revision that produced the event.
x-sbproxy-timestampUnix ms when the webhook was dispatched.
x-sbproxy-eventThe event type (e.g. ai.request.completed, policy.violation, audit.session_close).
x-sbproxy-signatureHMAC-SHA256 over the body, prefixed by the algorithm tag. Present when a signing secret is configured.
x-sbproxy-request-idThe originating request's correlation ID, propagated to the sink.

Mirror, shadow, and ledger traffic

HeaderWhere it goesDescription
x-sbproxy-mirror: 1The mirrored copy of the request sent to the mirror upstream (mirror.enabled: true)Lets the mirror target distinguish mirrored traffic from live traffic. Mirror responses are discarded; the client response carries nothing.
x-sbproxy-shadow: 1The shadow request sent by AI shadow trafficSame idea for the AI shadow path (crates/sbproxy-ai/src/client.rs).
x-sb-ledger-key-idThe outbound ledger POSTIdentifies the signing key for the usage-ledger submission (crates/sbproxy-modules/src/policy/ai_crawl/http_ledger.rs).
x-sb-ledger-signatureThe outbound ledger POSTDetached signature over the ledger submission body.

Not headers: OpenAPI vendor-extension keys

x-sbproxy-prefix-match, x-sbproxy-regex-path, and x-sbproxy-auth-type look like header names but are JSON keys in the OpenAPI document the proxy emits for an origin with expose_openapi: true. They annotate path items and security schemes in the spec (crates/sbproxy-openapi/src/lib.rs). They are never on the wire as HTTP headers.

Middleware helpers (RFC-shaped responses)

Two helpers produce response shapes that follow published RFCs. Both are opt-in per origin and fire on two error paths: proxy-generated errors (auth deny, policy deny, default 404) and upstream failures routed through Pingora's fail_to_proxy path (connect refused, connect timeout, TLS handshake error, mid-stream connection loss). See configuration.md for the per-origin config block.

Proxy-Status (RFC 9209)

Source: crates/sbproxy-middleware/src/proxy_status.rs. Stamped on non-2xx responses when the origin has proxy_status.enabled: true. The header carries the proxy identity (sbproxy by default; configurable per origin), the received upstream status, and a short error token sourced from the failure mode.

Proxy-Status: sbproxy; received-status=502; error="connection_refused"
Proxy-Status: sbproxy; received-status=504; error="connection_timeout"
Proxy-Status: sbproxy; received-status=502; error="tls_protocol_error"
Proxy-Status: sbproxy; received-status=502; error="connection_terminated"

The error token catalogue mirrors RFC 9209 section 2.3.4 (connection_refused, connection_timeout, tls_protocol_error, connection_terminated, http_request_error).

application/problem+json (RFC 9457)

Source: the render_problem_details function in crates/sbproxy-core/src/server.rs. Renders the response body as application/problem+json when the origin has problem_details.enabled: true and no custom error_pages entry matches the status. The body shape is the RFC 9457 problem details format with type, title, status, detail, instance fields.

{
  "type": "https://api.example.com/errors/502",
  "title": "Bad Gateway",
  "status": 502,
  "detail": "connection_refused",
  "instance": "/v1/orders"
}

an unauthenticated request answered with an RFC 9457 application/problem+json body

problem_details.enabled turns proxy-generated errors into typed problem documents (config).

On upstream failures the detail field carries the same RFC 9209 error token that lands in the Proxy-Status header so downstream tooling reading either signal sees the same vocabulary.

Debugging a live request

Send x-sb-flags: debug on the request and the proxy stamps x-sbproxy-debug-request-id and x-sbproxy-debug-config-rev on the response, plus a DEBUG-level log line keyed by the same request ID. For verbose process-wide logs, set RUST_LOG=debug on the proxy process.

Verifying live

Run any request through a configured proxy and inspect with curl:

curl -i -H "Host: myapp.example.com" http://127.0.0.1:8080/
# X-Request-Id: ee1f1806769b467bbaf5ca3550f17780
# traceparent: 00-dc5a693f...-dc3096404c44485a-01
# X-Sb-Session-Id: 01KQRPPS5FZ8MDQR0H01D0V52E   (when a session was captured)

X-Request-Id and traceparent appear on every response the proxy emits with default config. X-Sb-Session-Id appears when a session was captured for the request. Anything else you see is configured by the active sb.yml.