CWE-354: Improper Validation of Integrity Check Value
Overview
Improper integrity check validation occurs when an application does not verify a checksum, HMAC, or hash digest before trusting the data, or protects that data with a check that cannot resist tampering, such as CRC32. An attacker in a man-in-the-middle position, or with access to data at rest, can then alter the data and have the change accepted as genuine.
Risk
High: Missing or weak integrity checks let tampering go undetected: corrupted file downloads, modified API responses, manipulated cookies, and altered database records are all accepted as legitimate data.
Remediation Steps
Core Principle: Integrity checks must be verified correctly and enforced before use; reject any data that fails validation.
Locate the improper integrity check validation
- Find the code that receives data it should verify, and work out what is wrong with the check: there is no verification, the algorithm is weak (CRC32, MD5), the client supplies the checksum, or the HMAC is never compared
- Identify which data lacks integrity protection: file downloads, API responses, cookies, database records, configuration
- Trace where the checksum or HMAC should be verified and is not
Use strong integrity mechanisms (Primary Defense)
- For security:
- HMAC-SHA256 (message authentication) for API messages, cookies, and tokens that must resist tampering
- Digital signatures (RSA, ECDSA) for software updates, documents, and critical data that needs non-repudiation
- Authenticated encryption (AES-GCM) when data needs both confidentiality and integrity
- For corruption detection only:
- CRC32 and Adler32 detect accidental transmission errors, never tampering. Both are trivially forged: an attacker who changes the data can recompute the value to match.
- Where the expected digest comes from decides what a plain hash proves. SHA-256 and SHA-512 have no practical collision or preimage attack and do detect deliberate tampering, but only when the expected digest reaches the verifier independently of the data it describes: pinned in your own source, carried in a signed manifest, or fetched over a separate channel. A digest published beside the file it covers proves nothing, because whoever replaced the file replaced the digest. A keyless hash carries no authenticity of its own; that is what HMAC or a signature adds. See CWE-494 for the download case.
Verify integrity before use
- Compute the expected checksum or HMAC with the same algorithm and key
- Compare it with the value received, using a constant-time comparison such as
crypto.timingSafeEqual()orhmac.compare_digest()so the comparison does not leak timing - Reject the data when the check fails. Do not log the failure and carry on.
Protect integrity check value
- Keep the HMAC key on the server. Never send it to the client or embed it in client-side code.
- For public distribution, such as software updates, sign the checksum with a private key.
- Authenticated encryption (AES-GCM, ChaCha20-Poly1305) protects the data and its integrity tag together.
- A keyed tag belongs beside the data: HMAC and AEAD tags draw their strength from the key, not from where they are filed. AES-GCM appends its tag to the ciphertext by construction, and separating it buys nothing. It is the keyless digest that has to arrive from somewhere the attacker who controls the data cannot also control.
Implement end-to-end integrity
- Verify at the final destination, not at an intermediate node such as a proxy.
- Verify before decrypting, not after: under encrypt-then-MAC the tag covers the ciphertext, so the tag is checked first and a forged message never reaches the decryption routine at all. Decrypting first and checking the result afterwards is the ordering padding-oracle attacks feed on. AEAD modes (AES-GCM, ChaCha20-Poly1305) enforce this ordering for you, which is the main reason to prefer them over a hand-assembled cipher-plus-MAC.
- Verify the complete message, including headers, metadata, and payload, not just part of it.
Test the integrity validation fix
- Send a message with no HMAC or checksum and confirm it is rejected
- Modify the data and confirm it is rejected
- Send legitimate data with a correct checksum or HMAC and confirm it is accepted
- Confirm CRC32 and MD5 have been replaced with HMAC-SHA256 or stronger
- Re-scan with the security scanner to confirm the finding is resolved
Common Vulnerable Patterns
- Not verifying checksums at all
- Using CRC32 for security
- Weak hash for integrity (MD5)
- Client-controlled checksum values
- Missing HMAC verification
Additional Resources
- CWE-354: Improper Validation of Integrity Check Value
- NIST SP 800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC - GCM decryption verifies the tag before releasing any plaintext and returns FAIL otherwise, which is the ordering this page relies on
- OWASP Cheat Sheet Series
- OWASP Top 10 2025
- RFC 2104: HMAC: Keyed-Hashing for Message Authentication