netflix/lemur · Security

Lemur: JWT verifier honors attacker-supplied alg, enabling ATO

GHSA ID
GHSA-r9gp-7f88-9r54
CVE ID
CVE-2026-55165
Severity
medium
Published
Updated
CVSS
4.8 · CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
CVSS v3
4.8 · CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N

Description

Field Value
Title Lemur 1.9.0: JWT verifier trusts attacker-supplied alg from token header — defense-in-depth gap; chain-dependent ATO with secret disclosure
Component lemur/lemur/auth/service.py:130-137
CWE CWE-347 (Improper Verification of Cryptographic Signature)
Attack Prerequisite Defense-in-depth gap on its own — no single-request exploit against PyJWT 2.x. Single-request ATO requires a separate disclosure issue that leaks LEMUR_TOKEN_SECRET, or a future migration to asymmetric signing without fixing this sink.
Affected Versions github.com/Netflix/lemur version = "1.9.0". Same code present in every prior release that has the auth/service.py:130 block.

Exploit Code & Lab Set-up

Lemur-jwt-alg-hardening.zip

sequenceDiagram
    participant Attacker
    participant Lemur as Lemur API
    participant Disclosure as Disclosure surface
    participant Audit as Audit logging

    Note over Attacker,Lemur: "Today: PyJWT 2.x mitigation holds for alg=none"
    Attacker->>Lemur: "Bearer alg=none token with [payload]"
    Lemur->>Lemur: "pyjwt.decode raises (alg=none + non-None key)"
    Lemur-->>Attacker: "403 Forbidden"

    Note over Disclosure,Lemur: "Chain step: separate disclosure leaks LEMUR_TOKEN_SECRET"
    Attacker->>Disclosure: "trigger debug / SSRF / backup leak"
    Disclosure-->>Attacker: "LEMUR_TOKEN_SECRET value"

    Note over Attacker,Lemur: "Forge HS256 admin token with leaked secret"
    Attacker->>Lemur: "Bearer alg=HS256 admin token signed with leaked secret"
    Lemur->>Lemur: "algorithms=[HS256] (taken from header) — accepted"
    Lemur-->>Attacker: "200 OK, role=admin"

    Note over Audit: "alg=HS256 in audit log - no anomaly flag because attacker picks alg"

CWEs

References