KamoCRM

Carve out VOIPService's internal SMS-template API, and never forward a client's own X-Internal-Auth

FixAPIService
Shipped
September 23, 2026 at 10:24 AM UTC
Author
Kamo
Commit
8950a17

Two related gaps in the same trust boundary. /api/voip/sms/templates/** was forwarded wholesale by the /api/voip/** wildcard. VOIPService's InternalAuthFilter guards that prefix (and /api/bulktext/send) with a shared X-Internal-Auth secret, and SmsTemplateService trusts the org id carried in the request body once that check passes -- there is no further per-tenant check. That made an internal-only surface internet-reachable, with a single shared secret as the only thing standing between a stranger and every tenant's SMS templates. Added a carve-out mapping, the same mechanism already used for /api/voip/calls/** and /api/voip/recordings/** above it: more specific than the wildcard, so it wins regardless of declaration order, and returns 404 instead of forwarding. kamo-internal calls nothing under this path today (confirmed against origin/main), so nothing legitimate used this gateway to reach it. Separately: InboundHeaders never stripped X-Internal-Auth, so a client that guessed or leaked the shared secret could ride it through forward(), forwardWebhook() or forwardCallback() straight past whichever service's InternalAuthFilter was on the other end. It is added to IDENTITY_HEADERS -- it asserts a privilege ("I am trusted internal infrastructure") the same way the existing entries assert an identity, and dropping it is safe by construction: every controller in this service that legitimately acts as the internal caller (PublicChatController, PublicApiController, SocialWebhookController, VoipRecordingUploadController, VoipCallEventController, PublicChatKeyResolver) builds its outbound headers from scratch and sets this service's OWN configured secret -- none of them call InboundHeaders.copyInto, so none is affected. This entry is broader than Traefik's strip-identity-headers middleware, which does not yet strip it at the edge too; noting that as a follow-up for klusterservices rather than guessing at a cross-repo change here. VoipSmsTemplatesCarveOutTest covers the mapping and its 404 behaviour. IdentityHeaderStrippingTest's existing spoofed-request harness now also sends a guessed X-Internal-Auth on every case it already drives (billing, entitlements, the bulktext webhook, the OAuth callback), so this is covered on every forward path that type exercises, not only a new one. Reverting either change fails the corresponding test immediately.

All changes

Like what you see shipping?

All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.

Start Free ForeverView Pricing