Developer tools · JWT decoder
The alg:none Attack and Key Confusion: Why Verifiers Must Pin Algorithms
· Why it matters
jwt security cryptography
If a verifier lets the token choose its own algorithm, an attacker can choose none or swap RSA for HMAC. This post explains both attacks and the rule that prevents them.
The token that verified itself — how a header field became an attack surface
An algorithm label sits inside attacker-controlled token input. If a verifier treats that label as permission to select any available validation mode, the token begins influencing the rule used to judge itself. ToolAcre exposes the label precisely so reviewers can see it, but never acts on it cryptographically.
The safe direction is the reverse: trusted service configuration defines acceptable algorithm families and associated keys, then incoming headers must match that policy. A decode panel cannot supply that policy and must not be mistaken for protection simply because it highlights a suspicious value.
The repository flags alg:none but does not establish the specification history behind unsecured JWTs
The implementation treats `alg: none` as an unsigned declaration and warns that accepting it would accept arbitrary content. It also reports an empty third segment separately. The repository evidence supports rejecting such input in authenticated workflows; it does not document why unsecured JWTs were originally included in a specification.
That historical wording is therefore corrected rather than invented. What matters operationally is clear: a service expecting signed credentials must not allow a token header to disable signature checking. ToolAcre itself performs no verification, so its ability to display `none` is detection for inspection only.
The alg:none attack — stripping the signature and asking the verifier to accept an empty one
An unsigned attack changes the header to request `none`, changes claims if desired and supplies no signature bytes. Every segment can still be syntactically valid, and the first two decode into polished JSON. A permissive verifier would convert attacker preference into an authentication bypass.
A strict verifier has no branch that upgrades this input to trusted status when signed tokens are required. ToolAcre’s warning helps identify the shape during debugging, but reading the word `none` does not stop a backend from making a bad decision. Enforcement belongs where the credential is consumed.
Key confusion — presenting a public key as an HMAC secret so RS256 tokens are verified as HS256
Key confusion arises when a verifier permits algorithm families with incompatible key roles and fails to bind each choice to the correct key type. A public RSA verification key is not an HMAC secret. Treating its bytes as one after an attacker changes an algorithm label collapses the intended public/private separation.
Preventing that class of error requires more than checking for a signature-shaped segment. The service must pair expected algorithm, key type, issuer and token profile through trusted configuration. A decoder that shows RS256 or HS256 cannot tell whether the backend maintains those bindings.
The fix — pin the accepted algorithms in the verifier and never derive them from the token
Pin accepted algorithms in verifier configuration and keep the list as narrow as the issuer contract permits. Reject `none` for signed credential flows and reject mismatches rather than trying another algorithm. Do not derive the allow-list from the unverified header or from a payload claim.
Key lookup follows the same principle. A `kid` can select among already trusted candidates, but must not create a new trust source. Header URLs or embedded keys should not be followed merely because the token requests them. The verifier decides its sources independently.
Worked example — reading a header in the ToolAcre JWT decoder to spot alg:none, and why spotting it is not the same as being protected
Create a harmless token header declaring `none` and leave the third segment empty. ToolAcre decodes the JSON, reports the declared algorithm, warns that it is unsigned and notes the absent signature. This is exactly the behavior expected from an inspection tool.
The exercise does not prove that an API rejects the token. Confirm that separately with a controlled negative test against the actual verifier and configuration. If the API accepts it, the fix belongs in that verification boundary; adding a louder warning to a decoder would not protect requests.
What this does not cover — the many library-specific fixes; consult RFC 8725 and your library's changelog
Library APIs, defaults and historical fixes vary by product and version. This module does not establish which option name pins algorithms in your stack, and this article intentionally invents none. Read the selected library’s current documentation and changelog, then exercise rejection cases in your own test suite.
Also test wrong key types, unknown `kid` values, missing signatures and unexpected token profiles. The goal is to show that configuration wins over token suggestions. A successful decode belongs nowhere in these acceptance assertions because syntax success is compatible with every malicious example.
Takeaway: the verifier decides, not the token — a decoder helps you see the header, but only pinned verification protects you
The verifier decides; the token does not. ToolAcre can reveal a header that says `none`, an unfamiliar algorithm or a surprising key identifier. That visibility helps triage, but only pinned algorithm policy and correctly bound trusted keys prevent acceptance.
Never recommend enabling `none`, choosing a verification key from an untrusted header or treating a displayed signature length as validation. Decode for inspection, then prove rejection and acceptance behavior at the real cryptographic boundary with controlled tests.