Never forward client-supplied identity headers upstream

FixAPIService
Shipped
September 10, 2026 at 8:21 PM UTC
Author
Kamo
Commit
7d23fde

forward(), forwardWebhook() and forwardCallback() copied every inbound header except Host (and, for the sessionless two, the credential headers) onto the upstream request. BillingService is permitAll and takes the caller's org, member and god-mode claim from X-Org-Id, X-Member-Id and X-God-Mode-Active, so a request to api.<domain>/api/billing/** could act as any member, platform admins included. SecurityService's /api/security/entitlements/me reads X-Member-Id the same way. All three now copy through InboundHeaders.copyInto. It drops X-Org-Id, X-Member-Id, X-User-Id, X-God-Mode-Active, X-Member-Type, X-Public-Chat-Org-Id, X-Public-Chat-Key-Hash and any X-Sudo-* header, and logs the dropped names with the path and peer address. The headers are dropped unconditionally because no caller relies on the gateway carrying them. The legitimate senders (kamo-internal's billing, entitlements and LOS proxies, the e-sign clients, and this service's own key-validated controllers) all call the target service directly, and the 362 forward() calls still in the live pods' logs carried none of these headers. Stripe-Signature, carrier signatures, X-***-Token, X-OTK, Cookie and Authorization pass exactly as before. api-route now also runs the strip-identity-headers Traefik middleware first. That Middleware lives in KlusterServices and must be applied before this manifest, or Traefik rejects api-route and every api.* host 404s. IdentityHeaderStrippingTest drives every forward path with a spoofed request and inspects the upstream request. It also fails if any source file other than InboundHeaders enumerates client headers.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing