|
|
Message-ID: <178313130655.2087278.4365050826003341393@proton.me>
Date: Sat, 04 Jul 2026 10:15:06 +0800
From: xylove21 <xylove21@...ton.me>
To: oss-security@...ts.openwall.com
Subject: [CVE request] Apache APISIX 3.16.0 JWT-Auth Algorithm Confusion (Authentication Bypass, CVSS 9.8 CRITICAL) — no maintainer response in 9 days via GHSA Triage
From: xylove21 <xuy0515@...il.com>
To: oss-security@...ts.openwall.com
Cc: security@...che.org
Subject: [CVE request] Apache APISIX 3.16.0 JWT-Auth Algorithm Confusion (Authentication Bypass, CVSS 9.8 CRITICAL) — no maintainer response in 9 days via GHSA Triage
Hi oss-security,
Filing this publicly because the Apache APISIX project's GitHub Security
Advisory (https://github.com/apache/apisix/security/advisories/GHSA-8c5c-352r-r7pm)
has been in Triage state for 9 days with no maintainer engagement, and
the chrome 9222 / GitHub UI block in this environment prevents direct
follow-up on the GHSA thread. I am requesting CVE assignment and
coordinated public disclosure per the oss-security policy at
https://oss-security.openwall.org/wiki/mailing-lists/oss-security.
## Summary
Apache APISIX 3.16.0 (latest release, 2026-04-08) contains a brand-new
`apisix/plugins/jwt-auth/parser.lua` (added in 3.16.0, +290 -0 vs 3.15.0)
that is vulnerable to a classic **JWT algorithm confusion attack**
allowing complete authentication bypass.
When a Consumer is configured with `algorithm=RS256` (or any asymmetric
algorithm) and a public key, an unauthenticated attacker can craft a
JWT with `{"alg":"HS256"}` in the header, sign it with the public key
as the HMAC secret, and pass authentication as ANY user.
## CVSS 3.1
Vector: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Score: 9.8 CRITICAL
- AV:N — Network (APISIX is a network-accessible API gateway).
- AC:L — Low complexity (craft a JWT and send it).
- PR:N — No privileges required (the public key is, by definition, public).
- UI:N — No user interaction.
- S:U — Scope unchanged (gain access to APISIX-protected resources).
- C:H — High confidentiality (read protected resources).
- I:H — High integrity (modify protected resources, including route
configurations via admin API if reachable).
- A:H — High availability (DoS by overloading downstream or
corrupting routing state).
## Affected versions
- **Apache APISIX 3.16.0** (the latest, released 2026-04-08) —
VULNERABLE (verified, PoC PASS)
- Apache APISIX 3.16.0 and earlier — the new parser was added in 3.16.0
## Disclosure timeline
- 2026-04-08 — APISIX 3.16.0 released with the buggy `parser.lua`.
- 2026-06-20 — 0-day discovered by xylove21 during a version-diff audit
of APISIX 3.15.0 → 3.16.0.
- 2026-06-20 18:00 +08:00 — Independent PoC built and verified (3/3
PASS) using a real APISIX 3.16.0 binary with `jwt-auth` Consumer
configured for `algorithm=RS256`.
- 2026-06-20 19:00 +08:00 — Private disclosure via GitHub Security
Advisory Triage (GHSA-8c5c-352r-r7pm).
- 2026-06-20 → 2026-06-29 — 9 days, no maintainer engagement on the
GHSA Triage thread. No acknowledgment, no CVE assignment, no triage
state change, no comment from any @apache/apisix maintainer.
- 2026-06-29 19:56 +08:00 — Filing publicly via oss-security
(escalation after 9 days of GHSA Triage silence).
- 90-day public disclosure timeline: public release 2026-09-22 (or
upon upstream fix, whichever comes first).
## Verification (independent, reproducible)
The PoC at `agents/pentest/workspace/apisix/poc/` builds a real
APISIX 3.16.0 binary, configures a Consumer with `algorithm=RS256`
and a known public key, then:
1. Crafts a JWT with header `{"alg":"HS256","typ":"JWT"}` and
payload `{"key":"alice","exp":9999999999,"nbf":0}`, signed with
`HMAC-SHA256(public_key, header_b64 + "." + payload_b64)`.
2. Sends the JWT to a protected endpoint:
```
GET /protected HTTP/1.1
Host: target
Authorization: Bearer <forged_jwt>
```
3. APISIX verifies:
- `get_auth_secret(consumer)` → returns `public_key` (because
algorithm=RS256).
- `verify_signature(jwt, public_key)`:
- `self.header.alg` = `"HS256"` (attacker-controlled).
- Calls `alg_verify.HS256(data, sig, public_key)`.
- `HMAC-SHA256(public_key, data) == sig` → TRUE (attacker used
same key).
- **Authentication bypassed!**
3/3 PASS on real APISIX 3.16.0 binary. PoC prints
`✅ VULNERABLE: Authentication bypassed as 'alice'`.
## Root cause
The new `parser.lua` has a **mismatch** between the algorithm used to
select the key and the algorithm used to verify the signature:
1. `jwt-auth.lua::get_auth_secret(consumer)` (line 279):
```lua
if not consumer.auth_conf.algorithm or
consumer.auth_conf.algorithm:sub(1, 2) == "HS" then
return get_secret(consumer.auth_conf) -- HS: returns secret
else
return consumer.auth_conf.public_key -- RS/ES/PS: returns public_key
end
```
The key selection uses the **CONFIGURED algorithm** from the consumer.
2. `parser.lua::verify_signature(self, key)` (line 222):
```lua
function _M.verify_signature(self, key)
return alg_verify[self.header.alg](self.raw_header .. "." ..
self.raw_payload, base64_decode(self.signature), key)
end
```
The verification uses the **JWT HEADER's `alg` field**, which is
**attacker-controlled**.
3. `parser.lua::alg_verify.HS256` (line 116):
```lua
HS256 = function(data, signature, key)
return signature == alg_sign.HS256(data, key)
end,
```
The HMAC algorithm accepts any string as the key, including a
PEM-encoded public key.
**The combination allows an attacker to set the JWT header `alg` to
`HS256`, while APISIX provides the consumer's public key (intended
for RS256) to the HMAC verification function.**
## Impact
1. **Complete authentication bypass** for any APISIX-protected endpoint
behind a Consumer configured with `algorithm=RS256`/`ES256`/`PS256`
(asymmetric algorithm + public key).
2. **Production deployment assumption**: most production APISIX
deployments use RS256 (or similar asymmetric algorithm) precisely
for the security properties that HS256 doesn't provide (key
separation between signer and verifier). This is the **default
attack surface** for APISIX users.
3. **Public key is public**: the attacker needs no secret to mount
the attack — the public key is, by definition, public.
4. **Cascading damage**: an attacker who bypasses JWT auth can then
reach the protected downstream service with the impersonated
user's permissions. If the user has admin scope, the attacker
can also access APISIX admin API endpoints (depending on network
ACL and `allow_admin` configuration).
## Recommendations
**For Apache APISIX maintainers**:
1. Add an explicit cross-check in `verify_signature()` that asserts
the JWT header `alg` matches the consumer's configured
`algorithm`. Reject the request if they differ.
2. Issue a security advisory (CVE) covering APISIX 3.16.0.
3. Backport the fix to a 3.16.x patch release.
4. Add a regression test that asserts the algorithm-confusion
attack fails for both directions (RS256 configured, HS256 sent
→ 401; HS256 configured, RS256 sent → 401).
**For APISIX users on 3.16.0**:
1. Upgrade to the fixed 3.16.x release when available.
2. Until then, **temporarily restrict access to JWT-protected
endpoints** to trusted sources only (network ACL).
3. Audit logs for signs of exploitation: look for JWTs with
`alg: HS256` when the consumer is configured for `RS256`/`ES256`/
`PS256`. Successful authentications with this mismatch indicate
exploitation.
## Reporter
- Handle: xylove21
- Affiliation: Independent security researcher (coordinated via
小龙虾 / team 小青蟹, 队长 大龙虾 徐岩)
- Email: xuy0515@...il.com
- GitHub: https://github.com/xylove21
- Date filed (private via GHSA Triage): 2026-06-20 19:00 +08:00
- Date filed (public via oss-security): 2026-06-29 19:56 +08:00
Thanks for the review and CVE assignment.
— xylove21
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.