{"id":"GHSA-3prj-6hqw-cm82","summary":"PHP JWT Library: PBES2-HS*+A*KW unwrap accepts an unbounded p2c iteration count, enabling CPU-amplification denial of service","details":"### Impact\n\nWhen a JWE uses a password-based key-encryption algorithm (`PBES2-HS256+A128KW`, `PBES2-HS384+A192KW`, `PBES2-HS512+A256KW`), `PBES2AESKW::unwrapKey()` reads the `p2c` (PBKDF2 iteration count) parameter directly from the attacker-controlled JOSE header and passes it to `hash_pbkdf2()` with **no upper bound**. The only validation performed (`checkHeaderAdditionalParameters()`) was `is_int($p2c) && $p2c \u003e 0`.\n\nAn unauthenticated attacker can craft a single JWE whose protected header sets a very large `p2c` (e.g. `100_000_000` ≈ 87 s of CPU, or `PHP_INT_MAX`), forcing a worker to spend an arbitrary amount of CPU inside PBKDF2 **before** the key unwrap can even fail. The decrypter swallows the eventual exception, so the attacker pays almost nothing while the server burns CPU. JSON General serialization (multiple recipients) and multi-key JWKSets multiply the cost. This is a classic uncontrolled-resource-consumption (CWE-400) denial of service.\n\n### Affected configurations\n\nApplications that register any `PBES2-HS*+A*KW` algorithm in their decryption `AlgorithmManager`.\n\n### Patches\n\n`PBES2AESKW` now enforces a configurable maximum iteration count (`DEFAULT_MAX_COUNT = 1_000_000`, well above realistic legitimate values which are a few thousand) in `checkHeaderAdditionalParameters()`, before any PBKDF2 computation. The bound is exposed as a constructor argument so operators can tune it.\n\n### Workarounds\n\nBefore upgrading: validate/limit the `p2c` header with a custom header checker, or do not enable PBES2 algorithms for untrusted tokens.\n\n### References\n\n- RFC 7518 §4.8 (PBES2)\n- CWE-400: Uncontrolled Resource Consumption\n\n## Résolution\n\nUn correctif a été préparé sur une branche dédiée basée sur `3.4.x`, avec des tests anti-régression dédiés (fork privé temporaire de cette advisory, PR #1).\n\n**PBES2** — `PBES2AESKW::unwrapKey()` borne désormais le paramètre `p2c` (constante `DEFAULT_MAX_COUNT = 1_000_000`, configurable via le constructeur) avant tout appel à `hash_pbkdf2()`, empêchant l'amplification CPU (DoS).\n\n**Validation :** `php -l` OK, PHPUnit vert, aucune nouvelle erreur PHPStan introduite (différentiel nul vs `3.4.x`), aucun commentaire ajouté dans le code source. Après merge, cascade prévue `3.4.x → 4.0.x → 4.1.x`.","modified":"2026-07-15T22:00:51.234383465Z","published":"2026-06-18T21:09:01Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-06-18T21:09:01Z","nvd_published_at":null,"cwe_ids":["CWE-400","CWE-770"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/web-token/jwt-framework/security/advisories/GHSA-3prj-6hqw-cm82"},{"type":"WEB","url":"https://github.com/FriendsOfPHP/security-advisories/blob/master/web-token/jwt-library/GHSA-3prj-6hqw-cm82.yaml"},{"type":"PACKAGE","url":"https://github.com/web-token/jwt-framework"},{"type":"WEB","url":"https://github.com/web-token/jwt-framework/releases/tag/3.4.10"},{"type":"WEB","url":"https://github.com/web-token/jwt-framework/releases/tag/4.0.7"},{"type":"WEB","url":"https://github.com/web-token/jwt-framework/releases/tag/4.1.7"}],"affected":[{"package":{"name":"web-token/jwt-library","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-library"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.4.10"}]}],"versions":["3.3.0","3.3.1","3.3.2","3.3.3","3.3.4","3.3.5","3.4.0","3.4.1","3.4.2","3.4.3","3.4.4","3.4.5","3.4.6","3.4.7","3.4.8","3.4.9"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}},{"package":{"name":"web-token/jwt-framework","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-framework"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.4.10"}]}],"versions":["3.1.0","3.1.1","3.1.2","3.1.3","3.1.4","3.1.5","3.1.6","3.1.7","3.2.0","3.2.1","3.2.10","3.2.2","3.2.3","3.2.4","3.2.5","3.2.6","3.2.7","3.2.8","3.2.9","3.3.0","3.3.0-alpha1","3.3.0-alpha2","3.3.0-alpha3","3.3.1","3.3.2","3.3.3","3.3.4","3.3.5","3.4.0","3.4.1","3.4.2","3.4.3","3.4.4","3.4.5","3.4.6","3.4.7","3.4.8","3.4.9","v0.0.0","v0.0.1","v0.0.2","v0.1.0","v0.2.0","v0.2.1","v0.2.2","v0.2.3","v0.3.0","v0.3.1","v0.3.2","v0.4.0","v0.4.1","v0.5.0","v0.5.1","v0.5.2","v1.0.0","v1.0.1","v1.0.2","v1.0.3","v1.0.4","v1.0.5","v1.0.6","v1.1.0","v1.1.0-beta1","v1.1.0-beta2","v1.1.0-beta3","v1.1.0-beta4","v1.1.1","v1.1.2","v1.1.3","v1.1.4","v1.2.0","v1.2.1","v1.2.2","v1.2.3","v1.2.4","v1.3.0","v1.3.1","v1.3.10","v1.3.2","v1.3.3","v1.3.4","v1.3.5","v1.3.6","v1.3.7","v1.3.8","v1.3.9","v2.0.0","v2.0.0-alpha1","v2.0.0-alpha2","v2.0.0-alpha3","v2.0.1","v2.0.11","v2.0.12","v2.0.13","v2.0.2","v2.0.3","v2.0.4","v2.0.5","v2.0.6","v2.0.7","v2.0.8","v2.0.9","v2.1.0","v2.1.1","v2.1.2","v2.1.3","v2.1.4","v2.1.5","v2.1.6","v2.1.7","v2.1.8","v2.1.9","v2.2.0","v2.2.1","v2.2.10","v2.2.11","v2.2.2","v2.2.3","v2.2.4","v2.2.5","v2.2.6","v2.2.7","v2.2.8","v2.2.9","v3.0.1","v3.0.2","v3.0.3","v3.0.4","v3.0.5","v3.0.6","v3.0.7"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}},{"package":{"name":"web-token/jwt-library","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-library"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.0.0"},{"fixed":"4.0.7"}]}],"versions":["4.0.0","4.0.1","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}},{"package":{"name":"web-token/jwt-library","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-library"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.1.0"},{"fixed":"4.1.7"}]}],"versions":["4.1.0","4.1.1","4.1.2","4.1.3","4.1.4","4.1.5","4.1.6"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}},{"package":{"name":"web-token/jwt-framework","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-framework"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.0.0"},{"fixed":"4.0.7"}]}],"versions":["4.0.0","4.0.1","4.0.2","4.0.3","4.0.4","4.0.5","4.0.6"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}},{"package":{"name":"web-token/jwt-framework","ecosystem":"Packagist","purl":"pkg:composer/web-token/jwt-framework"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.1.0"},{"fixed":"4.1.7"}]}],"versions":["4.1.0","4.1.1","4.1.2","4.1.3","4.1.4","4.1.5","4.1.6"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-3prj-6hqw-cm82/GHSA-3prj-6hqw-cm82.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"}]}