Regex SHA-256 digest (hexadecimal)
A SHA-256 digest (FIPS 180-4) is 256 bits, i.e. 64 hexadecimal digits. The attempts I read differ in strictness: validator.js anchors and accepts both cases, the OCI image specification only allows lowercase a-f and states it without anchors, InQuest's IOC tool (iocextract) searches for the digest inside text so it accepts an 'x' glued before or a 'z' after, and hashID accepts any ':salt' suffix. Here's an anchored pattern accepting both cases and nothing else, compared against those attempts.
/^[a-fA-F0-9]{64}$/passes 25/25 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| validator.js (isHash, sha256) — identique à la recommandation : sert de référence | ^[a-fA-F0-9]{64}$ | 25 / 25 | safe |
| OCI image-spec — « /[a-f0-9]{64}/ » sans ancres et minuscules seules : 65 caractères, « x » collé et majuscules (refusées) sont mal traités | [a-f0-9]{64} | 14 / 25 | safe |
| iocextract (InQuest) — conçu pour extraire d'un texte : « x » ou « z » collés autour passent, 65 chiffres refusés par les frontières | (?:[^a-fA-F\d]|\b)([a-fA-F\d]{64})(?:[^a-fA-F\d]|\b) | 18 / 25 | safe |
| hashID — accepte un suffixe « :… » arbitraire (sel) après les 64 chiffres | ^[a-f0-9]{64}(:.+)?$ | 24 / 25 | safe |
Implementation
const re = new RegExp("^[a-fA-F0-9]{64}$", "");
re.test(input);Limits
- Valide seulement la FORME : 64 chiffres hexadécimaux. Rien ne distingue un SHA-256 d'un autre condensé de 256 bits (SHA3-256, BLAKE2s, SHA-512/256…), ni d'une chaîne hexadécimale quelconque de 64 caractères.
- Les préfixes « sha256: » (OCI, Docker) et « 0x » sont refusés ; retirez-les avant validation. Les deux casses sont acceptées : normalisez en minuscules pour comparer deux empreintes.
- Ne dit rien de l'intégrité : seule la comparaison avec une empreinte recalculée la prouve.