CVE-2026-62374: SD JWT JS: Tampered disclosures silently dropped instead of rejected
When one Disclosure in an SD-JWT presentation is tampered so its digest no longer matches the Issuer-signed _sd array, @sd-jwt/decode 0.19.0 does not reject the presentation. It silently drops the unmatched Disclosure and returns a reduced claim set, reporting success. The Issuer signature is untouched and valid.
This is a downgrade/omission primitive. A malicious or curious holder can present a tampered Disclosure and have the relying party receive fewer claims than the credential carries, with no error surfaced. Where the relying party does not enforce key binding, an in-transit (on-path) attacker can achieve the same by mangling one Disclosure’s bytes; where key binding is enforced, on-path tampering instead breaks the holder’s KB-JWT sd_hash binding (so it is rejected), and the downgrade is then exercisable by the key-bound holder — confirmed end-to-end with KB required.
Two distinct tampering inputs converge on the same silent-drop sink:
- Genuinely non-decodable Disclosure (broken base64url -> bytes that are not valid UTF-8, e.g. an injected
0xF2lead byte). RFC 9901 §7.1 step 3 / §4.2.1 require rejection.@sd-jwt/decodeinstead lossy-decodes it: theTextDecoder/Bufferpath substitutes U+FFFD (REPLACEMENT CHARACTER) for the invalid byte and recovers a syntactically valid disclosure (thesaltgains a U+FFFD, claimfamily_name="Smith"). The recovered Disclosure then hashes to a digest absent from the signed_sdarray, so it is silently skipped. - Tampered-but-still-valid-JSON Disclosure (digest no longer matches
_sd): same end state — the unmatched Disclosure is silently skipped.
Two RFC 9901 MUSTs compound:
- §7.1 step 5 (primary): “If any Disclosure was not referenced by digest value in the Issuer-signed JWT (directly or recursively via other Disclosures), the SD-JWT MUST be rejected.” — instead silently dropped.
- §7.1 step 3 / §4.2.1 (secondary): a non-base64url-JSON Disclosure MUST be rejected — the lenient lossy decode skips this check.
Confirmed end-to-end through SDJwtInstance.verify() with a real ES256 issuer key, and again with key binding REQUIRED (a valid holder ES256 KB-JWT over aud+nonce+sd_hash).
References
- github.com/advisories/GHSA-f9j6-8p6x-r9j6
- github.com/openwallet-foundation/sd-jwt-js/commit/3d8a72a0a279d67439db038c9c2b52621568b866
- github.com/openwallet-foundation/sd-jwt-js/pull/380
- github.com/openwallet-foundation/sd-jwt-js/security/advisories/GHSA-f9j6-8p6x-r9j6
- nvd.nist.gov/vuln/detail/CVE-2026-62374
Code Behaviors & Features
Detect and mitigate CVE-2026-62374 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Dependency Scanning using SBOM also detects vulnerabilities from proprietary advisories that this site does not include. Learn more about Dependency Scanning using SBOM →