Safeguard
Application Security•

ASVS 5.0 V11.3.4: Never Reuse a Nonce or IV

ASVS V11.3.4 requires single use numbers such as nonces and IVs to be unique per key and data element, generated the right way for the algorithm. Patterns that hold up.

Safeguard Security Team
3 min read

ASVS 5.0 V11.3.4 (Level 3) requires that nonces, initialization vectors and other single use numbers are never used for more than one key and data element pair, and that they are generated by a method suited to the algorithm in use.

Why it matters

Reuse is catastrophic for several common modes. With AES GCM, encrypting two messages under the same key and nonce reveals the XOR of the plaintexts and lets an attacker forge authentication tags. With CTR style modes the keystream repeats and the same XOR problem appears. With CBC a predictable IV enables chosen plaintext attacks.

The bug is silent. Every test passes, and the flaw sits in your data until someone looks.

How to implement it

First learn what your mode needs. The rules differ:

ModeRequirement
AES GCMUnique per key. 96 bit random is acceptable for limited volume, a counter is better at scale
ChaCha20 Poly1305Unique per key
AES CBCUnpredictable random IV per message
AES GCM SIVMisuse resistant, tolerates repeats better

Random 96 bit nonces under one key are safe only up to a limit on the number of messages; rotating keys keeps you under it. For heavy workloads use a counter per key, or derive per message keys.

Simple random pattern for moderate volume:

nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
    return nil, err // never continue with a zero nonce
}
sealed := gcm.Seal(nonce, nonce, plaintext, nil)

Counter pattern, where state must be durable and unique per key:

# one counter per key id, incremented atomically in the datastore
n = store.incr(f"nonce:{key_id}")
nonce = n.to_bytes(12, "big")

Never derive a nonce from a timestamp, a user id or a record id alone. Never copy an example's constant IV into production code. Store the nonce with the ciphertext; it need not be secret.

After restoring from a backup or cloning a virtual machine, a counter can rewind. Plan for that: include a random per instance prefix, or rotate to a fresh key after any restore.

How to test it

Review every encrypt call site and answer three questions: where does the nonce come from, is it unique per key, and what happens after restart or restore? Search for constants such as new byte[12] with no random fill, iv = b"0000", and fixed strings.

Then run a statistical check on stored data: extract the nonce prefix of every ciphertext under one key and assert no duplicates. For high volume systems also compute the message count per key and compare it to the algorithm limit.

Common mistakes

  • A hard coded IV copied from a tutorial
  • A zero nonce from an uninitialised buffer when the random call fails
  • Counters that reset on restart
  • Same nonce and key reused across two services
  • Using CBC with a sequential IV

Quick check

What happens if AES GCM reuses a nonce under one key?

Confidentiality leaks and attackers can forge tags, so integrity is lost too.

Must a nonce be secret?

No. It must be unique, and it is stored with the ciphertext.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.