The One-Line Flaw
Netflix's Lemur, a widely-used certificate management platform built on Flask, shipped a JWT verification flaw that security engineers have warned about for a decade. CVE-2026-55165, disclosed this week, reveals that Lemur's auth service reads the algorithm field directly from unverified tokens and passes it to PyJWT's decode function. The server trusts the attacker to specify how verification should work.
The fix is a single configuration line: pin the allowed algorithms to a server-side allowlist. But the vulnerability existed because the default behavior of most JWT libraries is permissive — they honor whatever algorithm the token header claims. Flask applications that rely on library defaults inherit this permissiveness.
The RS256-to-HS256 Attack Chain
The algorithm confusion attack is elegant in its simplicity. An attacker obtains the server's RSA public key — often available in JWKS endpoints or certificate stores. They then craft a token with the algorithm header set to HS256 instead of RS256. If the server doesn't pin algorithms, it treats the public key as an HMAC secret and validates the forged token.
In Lemur's case, the attack chain requires a disclosed LEMUR_TOKEN_SECRET to achieve full account takeover. But the vulnerability creates immediate audit blindness — logging records only attacker-supplied algorithm values, making forensic analysis unreliable.
Flask's Security Posture
Flask's minimalist philosophy — give developers the building blocks, let them assemble — creates a specific class of security risk. Unlike opinionated frameworks that enforce auth patterns, Flask leaves JWT implementation entirely to application developers. The result: 186 CVEs across the Flask ecosystem, with authentication misconfigurations representing a recurring pattern.
WebPulse tracks only 2 Flask-detected sites in its Tranco 100K scan, but Flask's real footprint is in internal tools, APIs, and microservices — exactly the kind of infrastructure where a certificate management platform like Lemur operates. These are high-value targets that don't appear in public-facing scans.
The Lesson for Framework Selection
CVE-2026-55165 is not a Flask vulnerability — it's an application vulnerability in code built on Flask. But the distinction matters less than the pattern. Frameworks that enforce security defaults (pinned algorithms, mandatory CSRF, opinionated auth) produce fewer of these misconfigurations. Frameworks that prioritize flexibility produce more.
For organizations evaluating web frameworks, the question is not whether Flask can be made secure. It can. The question is whether your team will consistently make the right security decisions in every authentication flow, every JWT handler, every token verification path — when the framework won't stop you from making the wrong one.


