CVE-2026-33204
SimpleJWT has an Unauthenticated Denial of Service via JWE header tampering
SimpleJWT is a simple JSON web token library written in PHP. Prior to version 1.1.1, an unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used. Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected. This issue has been patched in version 1.1.1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
SimpleJWT has an Unauthenticated Denial of Service via JWE header tampering
SimpleJWT is a simple JSON web token library written in PHP. Prior to version 1.1.1, an unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used. Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected. This issue has been patched in version 1.1.1.
- Record
CVE-2026-33204- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400
- Updated
- 2026-11-02
EUVDEUVD-2026-13871
7.5
SimpleJWT is a simple JSON web token library written in PHP. Prior to version 1.1.1, an unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used. Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected. This issue has been patched in version 1.1.1.
- Record
EUVD-2026-13871- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-xw36-67f8-339x
7.5
SimpleJWT has an Unauthenticated Denial of Service via JWE header tampering
Summary
An unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used.
Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected.
Details
PHP version: PHP 8.4.11
SimpleJWT version: v1.1.0
The relevant portion of the vulnerable implementation is shown below (PBES2.php):
<?php
/* ... SNIP ... */
class PBES2 extends BaseAlgorithm implements KeyEncryptionAlgorithm {
use AESKeyWrapTrait;
/** @var array<string, mixed> $alg_params */
static protected $alg_params = [
'PBES2-HS256+A128KW' => ['hash' => 'sha256'],
'PBES2-HS384+A192KW' => ['hash' => 'sha384'],
'PBES2-HS512+A256KW' => ['hash' => 'sha512']
];
/** @var truthy-string $hash_alg */
protected $hash_alg;
/** @var int $iterations */
protected $iterations = 4096;
/* ... SNIP ... */
/**
* Sets the number of iterations to use in PBKFD2 key generation.
*
* @param int $iterations number of iterations
* @return void
*/
public function setIterations(int $iterations) {
$this->iterations = $iterations;
}
/* ... SNIP ... */
/**
* {@inheritdoc}
*/
public function decryptKey(string $encrypted_key, KeySet $keys, array $headers, ?string $kid = null): string {
/** @var SymmetricKey $key */
$key = $this->selectKey($keys, $kid);
if ($key == null) {
throw new CryptException('Key not found or is invalid', CryptException::KEY_NOT_FOUND_ERROR);
}
if (!isset($headers['p2s']) || !isset($headers['p2c'])) {
throw new CryptException('p2s or p2c headers not set', CryptException::INVALID_DATA_ERROR);
}
$derived_key = $this->generateKeyFromPassword($key->toBinary(), $headers);
return $this->unwrapKey($encrypted_key, $derived_key, $headers);
}
/* ... SNIP ... */
/**
* @param array<string, mixed> $headers
*/
private function generateKeyFromPassword(string $password, array $headers): string {
$salt = $headers['alg'] . "\x00" . Util::base64url_decode($headers['p2s']);
/** @var int<0, max> $length */
$length = intdiv($this->getAESKWKeySize(), 8);
return hash_pbkdf2($this->hash_alg, $password, $salt, $headers['p2c'], $length, true);
}
}
?>
The security flaw lies in the lack of input validation when handling JWEs that uses PBES2.
A "sanity ceiling" is not set on the iteration count, which is the parameter known in the JWE specification as p2c (RFC7518).
The library calls decryptKey() with the untrusted input $headers which then use the PHP function hash_pbkdf2() with the user-supplied value $headers['p2c'].
This results in an algorithmic complexity denial-of-service (CPU exhaustion) because the PBKDF2 iteration count is fully attacker-controlled.
Because the header is processed before successful decryption and authentication, the attack can be triggered using an invalid JWE, meaning authentication is not required.
Proof of Concept
Spin up a simple PHP server which accepts a JWE as input and tries to decrypt the user supplied JWE.
mkdir simplejwt-poc
cd simplejwt-poc
composer install
composer require kelvinmo/simplejwt
php -S localhost:8000
The content of index.php:
<?php
require __DIR__ . '/vendor/autoload.php';
$set = SimpleJWT\Keys\KeySet::createFromSecret('secret123');
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if ($uri === '/encrypt' && $method === 'GET') {
// Note $headers['alg'] and $headers['enc'] are required
$headers = ['alg' => 'PBES2-HS256+A128KW', 'enc' => 'A256CBC-HS512'];
…
- Record
GHSA-xw36-67f8-339x- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400
- Updated
- 2026-11-02
NVD
7.5
SimpleJWT is a simple JSON web token library written in PHP. Prior to version 1.1.1, an unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used. Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected. This issue has been patched in version 1.1.1.
- Record
CVE-2026-33204- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400
- Updated
- 2026-11-02
OSV
7.5
SimpleJWT has an Unauthenticated Denial of Service via JWE header tampering
SimpleJWT is a simple JSON web token library written in PHP. Prior to version 1.1.1, an unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used. Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected. This issue has been patched in version 1.1.1.
- Record
CVE-2026-33204- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400
- Updated
- 2026-11-02
OSVGHSA-xw36-67f8-339x
7.5
SimpleJWT has an Unauthenticated Denial of Service via JWE header tampering
Summary
An unauthenticated attacker can perform a Denial of Service via JWE header tampering when PBES2 algorithms are used.
Applications that call JWE::decrypt() on attacker-controlled JWEs using PBES2 algorithms are affected.
Details
PHP version: PHP 8.4.11
SimpleJWT version: v1.1.0
The relevant portion of the vulnerable implementation is shown below (PBES2.php):
<?php
/* ... SNIP ... */
class PBES2 extends BaseAlgorithm implements KeyEncryptionAlgorithm {
use AESKeyWrapTrait;
/** @var array<string, mixed> $alg_params */
static protected $alg_params = [
'PBES2-HS256+A128KW' => ['hash' => 'sha256'],
'PBES2-HS384+A192KW' => ['hash' => 'sha384'],
'PBES2-HS512+A256KW' => ['hash' => 'sha512']
];
/** @var truthy-string $hash_alg */
protected $hash_alg;
/** @var int $iterations */
protected $iterations = 4096;
/* ... SNIP ... */
/**
* Sets the number of iterations to use in PBKFD2 key generation.
*
* @param int $iterations number of iterations
* @return void
*/
public function setIterations(int $iterations) {
$this->iterations = $iterations;
}
/* ... SNIP ... */
/**
* {@inheritdoc}
*/
public function decryptKey(string $encrypted_key, KeySet $keys, array $headers, ?string $kid = null): string {
/** @var SymmetricKey $key */
$key = $this->selectKey($keys, $kid);
if ($key == null) {
throw new CryptException('Key not found or is invalid', CryptException::KEY_NOT_FOUND_ERROR);
}
if (!isset($headers['p2s']) || !isset($headers['p2c'])) {
throw new CryptException('p2s or p2c headers not set', CryptException::INVALID_DATA_ERROR);
}
$derived_key = $this->generateKeyFromPassword($key->toBinary(), $headers);
return $this->unwrapKey($encrypted_key, $derived_key, $headers);
}
/* ... SNIP ... */
/**
* @param array<string, mixed> $headers
*/
private function generateKeyFromPassword(string $password, array $headers): string {
$salt = $headers['alg'] . "\x00" . Util::base64url_decode($headers['p2s']);
/** @var int<0, max> $length */
$length = intdiv($this->getAESKWKeySize(), 8);
return hash_pbkdf2($this->hash_alg, $password, $salt, $headers['p2c'], $length, true);
}
}
?>
The security flaw lies in the lack of input validation when handling JWEs that uses PBES2.
A "sanity ceiling" is not set on the iteration count, which is the parameter known in the JWE specification as p2c (RFC7518).
The library calls decryptKey() with the untrusted input $headers which then use the PHP function hash_pbkdf2() with the user-supplied value $headers['p2c'].
This results in an algorithmic complexity denial-of-service (CPU exhaustion) because the PBKDF2 iteration count is fully attacker-controlled.
Because the header is processed before successful decryption and authentication, the attack can be triggered using an invalid JWE, meaning authentication is not required.
Proof of Concept
Spin up a simple PHP server which accepts a JWE as input and tries to decrypt the user supplied JWE.
mkdir simplejwt-poc
cd simplejwt-poc
composer install
composer require kelvinmo/simplejwt
php -S localhost:8000
The content of index.php:
<?php
require __DIR__ . '/vendor/autoload.php';
$set = SimpleJWT\Keys\KeySet::createFromSecret('secret123');
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if ($uri === '/encrypt' && $method === 'GET') {
// Note $headers['alg'] and $headers['enc'] are required
$headers = ['alg' => 'PBES2-HS256+A128KW', 'enc' => 'A256CBC-HS512'];
…
- Record
GHSA-xw36-67f8-339x- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
kelvinmo/simplejwtPackagist |
through 1.1.0 | 1.1.1 |
kelvinmo/simplejwtPackagist |
before 1.1.1, plus listed versions v0.1.0v0.1.1v0.1.2v0.1.3v0.1.4 Show 36 moreShow lessv0.1.5v0.1.6v0.2.1v0.2.2v0.2.3v0.2.4v0.2.5v0.3.0v0.3.1v0.4.0v0.4.1v0.4.2v0.5.0v0.5.1v0.5.2v0.5.3v0.6.0v0.6.0-rc.1v0.6.0-rc.2v0.6.1v0.6.2v0.6.3v0.7.0v0.7.1v0.8.0v0.8.1v0.8.2v0.9.0v0.9.1v0.9.2v0.9.3v1.0.0v1.0.1v1.0.2v1.0.3v1.1.0 |
1.1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-33204 is a high vulnerability (CVSS 7.5) in Kelvinmo Simplejwt, published March 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.50%, the 43rd percentile. Fixed in kelvinmo/simplejwt 1.1.1.
References
github.com/kelvinmo/simplejwt/security/advisories/GHSA-xw36-67f8-339x
github.com/kelvinmo/simplejwt/releases/tag/v1.1.1
nvd.nist.gov/vuln/detail/CVE-2026-33204
github.com/advisories/GHSA-xw36-67f8-339x
github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33204.json
github.com/kelvinmo/simplejwt
Left out here: the rest of 2 source descriptions. The JSON record has them.