Authorization bypass in 8x8’s JaaS SIP calling gateway
Jitsi as a Service (JaaS) — 8x8 SIP gateway
OffSeq found an authorization bypass in the JaaS SIP gateway, the outbound-calling service behind 8x8's Jitsi as a Service platform. The invite endpoint decided whether a tenant may place outbound SIP calls by reading a feature flag out of the caller's own token — a value the tenant sets — rather than the tenant's provisioned entitlement. Any JaaS tenant without the paid SIP-outbound feature could therefore make 8x8's trunk dial an attacker-chosen destination, with an attacker-controlled caller ID presented from @8x8.vc. 8x8 fixed it over two rounds through their HackerOne program.
Severity: MediumCVSS5.87 min read
§ 01. Overview
Jitsi as a Service (JaaS) is 8x8's hosted version of the Jitsi Meet stack: tenants embed video meetings in their own products using a per-tenant AppID and an API key. One of its paid features is SIP outbound — the ability for a meeting to dial a phone or SIP endpoint through 8x8's telephony trunk. Whether a tenant is entitled to that feature is part of their subscription, recorded server-side.
OffSeq found that the SIP gateway did not enforce that entitlement. The endpoint that places the call, POST /sip-jibri-gateway/jibris/invite, read the sip-outbound-call feature flag out of the caller's JSON Web Token and trusted it — but JaaS tokens are self-signed with the tenant's own API key, so the tenant, not 8x8, decides what that flag says. A tenant with no SIP-outbound entitlement could assert the flag in a token it signs itself and place a real outbound call. Because the destination is attacker-chosen and the From identity is delivered from @8x8.vc, the same gap is a toll-fraud and caller-ID-spoofing primitive. 8x8 addressed it in two remediation rounds.
§ 02. Tenant tokens and the SIP gateway
A JaaS tenant authenticates to the API with a JWT it signs using its own API key (kid = <AppID>/<keyId>). The token carries a context.features object describing what the session may do — recording, transcription, SIP outbound, and so on. In the product this object is populated by 8x8's UI to mirror the tenant's plan, and the client only offers the SIP-invite button when context.features["sip-outbound-call"] is enabled. That is a client-side convenience, not a security boundary: the tenant holds the signing key, so it can put any values it likes into a token it mints.
The gateway exposes the call itself at:
POST https://api-vo.cloudflare.jitsi.net/sip-jibri-gateway/jibris/inviteThe request names a target meeting through callParams.callUrlInfo.baseUrl = https://8x8.vc/<AppID> and one or more SIP destinations in sipClientParams.sipAddress (an array). The authoritative view of what a tenant is actually provisioned for is published by 8x8's own actuator, which lists the features a tenant does not have:
GET /jaas-actuator/v1/public/tenants/<AppID>
disabledFeatures = ["outbound-call","sip-outbound-call","recording","livestreaming","transcription"]The test tenant used throughout this disclosure (vpaas-magic-cookie-514344fe95db4894bd93aa8a803e3cdc) has sip-outbound-call in disabledFeatures — it is not provisioned for SIP outbound. That is the fact the gateway was supposed to check, and did not.
§ 03. Root cause: authorizing on a self-asserted claim
The endpoint made its authorization decision from the token's sip-outbound-call claim instead of the tenant's real entitlement. Since the tenant signs its own token, the claim is attacker-controlled: asserting sip-outbound-call: "true" in a self-signed JWT is enough to be treated as entitled, regardless of the subscription. This is CWE-863 (incorrect authorization) reached through CWE-807 (relying on an untrusted input for a security decision).
What makes it unambiguous is the contrast with 8x8's own other features. For recording and transcription, the same class of self-signed token from the same non-entitled tenant is refused — the gateway answers <error type="auth"><forbidden/></error>, because those paths authorize against the tenant's provisioned entitlement rather than the token's claim. SIP outbound was the one feature that trusted the claim.
A second, related gap sat alongside it: the target meeting's tenant (baseUrl) was not bound to the token's sub, so a token for one tenant could drive a call attributed to another — cross-tenant attribution of the activity and its cost.
§ 04. Proof of concept
The behaviour was demonstrated end to end against a host OffSeq controls, listening on UDP 5060. A single invite, carrying a self-signed token from the non-entitled test tenant, is enough:
POST /sip-jibri-gateway/jibris/invite HTTP/1.1
Host: api-vo.cloudflare.jitsi.net
Authorization: Bearer <self-signed JaaS JWT; context.features.sip-outbound-call = "true">
Content-Type: application/json
{
"callParams": {
"callUrlInfo": { "baseUrl": "https://8x8.vc/<AppID>", "callName": "offseqsipproof" },
"passcode": null
},
"sipClientParams": { "displayName": "OffSeq-PoC", "sipAddress": ["sip:offseq@<host-we-control>:5060"] }
}The gateway accepts it and reports the invite as placed:
HTTP/1.1 200
{"successfulInvites":[{"sipAddress":"sip:offseq@<host-we-control>:5060"}],"failedInvites":[]}Within seconds, 8x8's SIP infrastructure sends a genuine INVITE — retransmitted over several seconds, a real call setup, which the host intentionally did not answer — with a full audio+video SDP offer and an attacker-supplied display name delivered from @8x8.vc:
IP 3.147.160.14.5060 > <our-host>.5060: SIP: INVITE sip:offseq@<our-host> SIP/2.0
From: "OffSeq-PoC" <sip:[email protected]>;tag=...
To: <sip:offseq@<our-host>>
Via: SIP/2.0/UDP 3.147.160.14:5060 ; SIP/2.0/UDP 108.177.136.5:5090
Contact: <sip:[email protected]:5090>
Content-Type: application/sdp (m=audio opus/PCM/AMR + m=video H264/VP8, a=sendrecv)Every invite in this work was aimed only at hosts and tenants OffSeq controls; no PSTN, premium-rate or third-party number was dialed, and request volume was kept to the minimum needed to prove the behaviour.
§ 05. Impact and severity
The finding was published at CVSS 5.8 (Medium) — revised down from an initial Critical assessment once it was established that the vector needs a tenant token rather than being fully unauthenticated. Within that model the impact is concrete:
- Toll fraud. A tenant without the paid SIP-outbound feature makes 8x8's trunk place outbound calls to destinations it chooses.
sipAddressis an array, so a single request can fan out to many destinations — cost amplification. Aimed at a PSTN or premium-rate gateway, this is direct monetary loss. - Paid-feature bypass. The SIP-outbound entitlement is simply not enforced; a non-provisioned tenant uses it anyway.
- Cross-tenant attribution. Because the call's target tenant is not bound to the token, activity and cost can be attributed to a victim tenant.
- Caller-ID / identity spoofing. The attacker-controlled display name is delivered from
@8x8.vc, borrowing 8x8's trusted trunk identity for phishing or vishing.
The severity is moderated by the tenant-token requirement, but the primitive — an unauthorized outbound call on a trusted telephony trunk, with a spoofable identity — is exactly the kind a fraud or social-engineering operation wants.
§ 06. The fix, in two rounds
8x8's first fix, deployed for the initial retest, blocked the literal proof of concept: the gateway began reading the sip-outbound-call claim (so the original token, which carried false, was refused) and bound sub to baseUrl (closing the cross-tenant vector). But it read the claim from the token — the value the tenant controls — so the underlying authorization flaw was untouched. OffSeq's retest showed the bypass with a one-field edit to the same self-signed token:
| Token presented | sip-outbound-call claim | Gateway response |
|---|---|---|
| none | — | 401 Unauthorized |
| self-signed, entitlement absent | false (original PoC) | 403 Forbidden |
| self-signed, entitlement absent | true | 200 · call placed |
self-signed, entitlement absent, cross-tenant baseUrl | true | 403 Forbidden |
true. The cross-tenant vector is closed.The remedy is the one 8x8's other features already applied — authorize against the tenant's real entitlement (its disabledFeatures), not the self-asserted claim. 8x8's second fix did exactly that. On the final retest, the same self-signed sip-outbound-call: "true" token that had placed a call now returns 403 Forbidden, while an unauthenticated request still returns 401 — proof the endpoint reaches a genuine per-request authorization decision after authenticating, rather than being blanket-disabled. The 403 bodies are the application's own JSON ({"messageKey":"forbidden","path":"/sip-jibri-gateway/jibris/invite"}), not an edge block.
§ 07. Disclosure and outcome
The vulnerability was reported to 8x8 through their HackerOne program on 2 July 2026 and triaged the same day at Medium (5.8). OffSeq's first retest (6 July) showed the initial fix could be bypassed by asserting the claim; a second fix followed, and OffSeq's second retest (13 July) confirmed it holds. 8x8 resolved the report, and it was publicly disclosed on 12 August 2026.
§ 08. Disclosure timeline
- 2026-07-02OffSeq reports the outbound-SIP authorization bypass to 8x8 via HackerOne; triaged the same day and revised from an initial Critical to Medium (5.8)
- 2026-07-06First fix deployed; OffSeq's retest shows the bypass persists — the gateway now reads the JWT's own SIP-outbound claim, which the tenant controls
- 2026-07-09Second fix deployed after the retest; 8x8 requests another verification
- 2026-07-13OffSeq confirms the second fix holds; 8x8 marks the report Resolved
- 2026-08-12Report publicly disclosed
