JWSVerifier::getAlgorithm() merged the protected and unprotected headers
with [...$protected, ...$unprotected]; with duplicate keys PHP keeps the
LAST value, so the attacker-controlled unprotected header could override
the integrity-protected "alg". Combined with HeaderCheckerManager (which
validates "alg" from the protected header), this is a TOCTOU
algorithm-confusion / downgrade vector (e.g. forcing HS256 against an RSA
public key, or HS512 -> HS256), and "alg" placed only in the unprotected
header bypassed the duplicate-parameter check entirely.
Per RFC 7515 §4.1.1 "alg" MUST be integrity protected. getAlgorithm() now
reads "alg" exclusively from the protected header and rejects a JWS whose
"alg" is absent from (or present only outside) the protected header.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>