Jun 18, 2026·7 min read·4 visits
A flaw in the way PHP JWT Framework merges headers allows parameters in unprotected headers to overwrite those in protected headers, leading to cryptographic signature bypass via algorithm confusion.
An algorithm confusion vulnerability exists in the PHP JWT Framework (web-token/jwt-library) where the JWSVerifier and JWEDecrypter components merge integrity-protected and unprotected headers using insecure methods. Under specific conditions, duplicate parameters defined in unprotected headers override those in integrity-protected headers, allowing an attacker to bypass cryptographic signature verification.
The PHP JWT Framework (web-token/jwt-framework) is an implementation of JWT, JWS, JWE, and JWK specifications. Within this framework, JSON Web Signatures (JWS) and JSON Web Encryption (JWE) operations are handled by the JWSVerifier and JWEDecrypter helper classes. These classes process cryptographic tokens which may contain both integrity-protected headers (defined in the protected segment of the token) and unprotected headers (defined in the header segment of a JSON Flattened or General serialized JWS/JWE payload).
The attack surface exists in the parser's validation pipeline, where incoming tokens are examined. Integrity-protected headers are base64url-encoded and cryptographically bound to the signature. Unprotected headers, conversely, are transmitted in plain JSON format without verification, allowing an attacker to alter their values arbitrarily without invalidating the token structure itself.
This vulnerability, classified under CWE-345 (Active Verification of Cryptographic Signature), occurs when the logic designed to merge these headers allows unprotected parameters to supersede integrity-protected parameters. When critical values such as the signature algorithm (alg) or encryption algorithm (enc) are overridden, the framework relies on unauthenticated data to execute cryptographic operations.
The underlying flaw stems from the use of unsafe array merging behavior when combining protected and unprotected headers in PHP. In PHP 8.1, array unpacking via the spread operator (...) was introduced for string-keyed arrays. This operator, alongside the legacy array_merge() function, exhibits an overwrite behavior where values from subsequent arrays replace values from prior arrays if keys are identical.
In src/Library/Signature/JWSVerifier.php, the library merges headers inside the JWSVerifier::getAlgorithm() method using the following code path:
$completeHeader = [...$signature->getProtectedHeader(), ...$signature->getHeader()];Here, $signature->getProtectedHeader() contains parameters validated by the cryptographic signature, while $signature->getHeader() contains unauthenticated parameters from the unprotected header segment. Because the unprotected header is unpacked second, duplicate keys in the unprotected header overwrite those in the protected header.
This behavior exposes a Time-of-Check to Time-of-Use (TOCTOU) vulnerability. During the 'Time-of-Check' phase, the framework uses the HeaderCheckerManager to validate parameters. This validator inspects the protected header's alg parameter (for instance, verifying that the algorithm is a permitted asymmetric algorithm like RS256). During the subsequent 'Time-of-Use' phase, JWSVerifier processes the token using the overridden algorithm from the unprotected header (for instance, a symmetric algorithm like HS256), bypassing the validation checks completed during the initial step.
A corresponding vulnerability exists in src/Library/Encryption/JWEDecrypter.php during key management processing. The class merges headers using the following instruction:
$completeHeader = array_merge(
$jwe->getSharedProtectedHeader(),
$jwe->getSharedHeader(),
$recipient->getHeader()
);Because the unprotected shared headers (getSharedHeader()) and recipient headers (getHeader()) are appended after the protected header, an attacker can override critical decryption parameters (alg and enc) and control the key unwrapping logic.
The following code blocks illustrate the vulnerable header merging logic and the subsequent remediation applied to secure the cryptographic parameter extraction.
In the vulnerable implementation, the merged header structure was passed directly to the algorithm resolution manager:
// VULNERABLE
private function getAlgorithm(Signature $signature): Algorithm
{
// Unprotected headers overwrite protected headers due to the spread operator order
$completeHeader = [...$signature->getProtectedHeader(), ...$signature->getHeader()];
if (!isset($completeHeader['alg'])) {
throw new InvalidArgumentException('No "alg" parameter found.');
}
return $this->signatureAlgorithmManager->get($completeHeader['alg']);
}The patched implementation addresses the issue by retrieving cryptographic metadata exclusively from the protected header context:
// PATCHED
private function getAlgorithm(Signature $signature): Algorithm
{
// Read parameter strictly from the cryptographically bound protected header
$protectedHeader = $signature->getProtectedHeader();
if (!isset($protectedHeader['alg'])) {
throw new InvalidArgumentException('The "alg" parameter must be in the protected header.');
}
return $this->signatureAlgorithmManager->get($protectedHeader['alg']);
}By querying $signature->getProtectedHeader() rather than $completeHeader, the resolver ignores any injected alg parameter present in the unprotected segment.
A similar fix was implemented within JWEDecrypter.php to retrieve key management and encryption parameters exclusively from the integrity-protected $jwe->getSharedProtectedHeader() and appropriate recipient headers, avoiding the insecure merge pattern entirely.
Exploitation relies on an algorithm confusion technique. This occurs when an asymmetric algorithm (such as RSA or ECDSA) is downgraded to a symmetric algorithm (such as HMAC). In asymmetric setups, the server uses a public key to verify signatures. If the server is tricked into using a symmetric algorithm, it uses that public key as a secret key to compute and verify the HMAC signature.
An attacker crafts a token leveraging JSON Flattened JWS serialization. The JSON structure is defined as follows:
{
"payload": "eyJzdWIiOiJhZG1pbiIsImV4cCI6MTkwMDAwMDAwMH0",
"protected": "eyJhbGciOiJSUzI1NiJ9",
"header": {
"alg": "HS256"
},
"signature": "u6_malicious_hmac_signature_using_public_key_here"
}The target application processes this token using the sequence described in the following diagram:
To construct the signature, the attacker obtains the application's public RSA key (which is frequently public-facing in JWT/OIDC endpoints) and uses it as a symmetric HMAC key to generate the HMAC-SHA256 signature over the payload. During verification, the library validates the protected header's RS256 algorithm, proceeds to overwrite the active algorithm with HS256, and performs symmetric HMAC verification using the public key. Because the attacker computed the HMAC signature with that same public key, the cryptographic check succeeds, granting arbitrary authorization.
A successful compromise of this verification logic allows an attacker to construct valid JWT payloads containing arbitrary claims. By spoofing identity tokens, an attacker can bypass authorization constraints, impersonate administrative accounts, and perform unauthorized operations within the affected infrastructure.
The CVSS v4.0 score is rated at 8.1, with the vector CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P. The attack complexity is evaluated as High because the exploit is only viable under specific environmental conditions, such as when the system is configured to verify tokens using a JSON Web Key Set (JWKSet) that mixes symmetric and asymmetric keys, or when developers invoke JWSVerifier directly without integrating the HeaderCheckerManager component.
If the application implements proper header checks independently or limits key sets to uniform cryptographic families, the probability of successful exploitation is mitigated. However, if the JWKSet contains mixed-type keys, the impact on integrity and confidentiality is critical.
To address this vulnerability, administrators and developers must upgrade the underlying web-token/jwt-library packages to the designated secure versions.
If an immediate dependency upgrade is not possible, apply code modifications to manually inspect the structure of incoming tokens prior to verification. Ensure that parameters defined in the unprotected header cannot overwrite protected options:
// Prevent verification if 'alg' or 'enc' is defined in unprotected headers
$unprotectedHeader = $jws->getHeader();
if (isset($unprotectedHeader['alg']) || isset($unprotectedHeader['enc'])) {
throw new SecurityException('Rejected: Critical parameters present in unprotected header.');
}Additionally, developers must separate key repositories. Do not combine symmetric secrets (HMAC) and asymmetric keys (RSA/EC) in the same JWKSet definition. This segregation ensures that the verification pipeline cannot access a public key when executing symmetric signature algorithms.
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P| Product | Affected Versions | Fixed Version |
|---|---|---|
web-token/jwt-library web-token | < 3.4.10 | 3.4.10 |
web-token/jwt-library web-token | >= 4.0.0, < 4.0.7 | 4.0.7 |
web-token/jwt-library web-token | >= 4.1.0, < 4.1.7 | 4.1.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-345 (Active Verification of Cryptographic Signature) |
| Attack Vector | Network (AV:N) |
| CVSS v4.0 Score | 8.1 |
| Exploit Status | Proof of Concept |
| Vulnerability Type | Cryptographic Bypass / Algorithm Confusion |
| Affected Component | JWSVerifier and JWEDecrypter |
The software does not verify, or incorrectly verifies, the cryptographic signature for data.
A critical mass-assignment (property injection) vulnerability exists in the PHP One-Time Password (OTP) library spomky-labs/otphp within the Factory::loadFromProvisioningUri method. When an application loads an OTP provisioning URI (such as a QR code configuration link), a hostile URI can inject query parameters that dynamically overwrite internal, private, or read-only object properties of the OTP instance. This behavior leads to application state corruption, validation bypasses, or uncaught TypeErrors that crash the executing application process.
An implementation flaw in the experimental Chacha20Poly1305 key-encryption algorithm within the PHP JWT Framework (web-token/jwt-framework) discards the Poly1305 authentication tag during key wrapping and omits it during decryption. This degrades the Authenticated Encryption with Associated Data (AEAD) protection to unauthenticated ChaCha20, allowing an attacker to manipulate the encrypted Content Encryption Key (CEK) without detection.
An uncontrolled resource consumption vulnerability in the PBES2-HS* key wrapping algorithms of the web-token JWT library allows remote, unauthenticated attackers to cause a denial of service (DoS) by sending JWE tokens with unbounded iteration counts.
An observable timing discrepancy vulnerability in the web-token/jwt-framework library allows unauthenticated remote attackers to perform a Bleichenbacher / Marvin padding oracle attack against JWE tokens using the RSAES-PKCS1-v1_5 algorithm. By failing to perform constant-time implicit rejection on PKCS#1 v1.5 padding failures, the decryption process leaks structural validation errors via exceptions and early returns, exposing the wrapped Content Encryption Key (CEK) to cryptographic recovery.
An unauthenticated authentication bypass vulnerability exists in @acastellon/auth, an authorization middleware package for Express-based microservices. The vulnerability allows a remote, unauthenticated attacker to completely bypass token validation checks in the validateToken() middleware via spoofed HTTP headers.
A technical analysis of SQL injection vulnerabilities affecting Budibase's database connectors for PostgreSQL, Microsoft SQL Server, and MySQL. Due to direct concatenation of schema and table identifiers into raw SQL queries, authenticated administrative users or malicious database schemas can execute arbitrary SQL commands.