Cryptography

Length Extension Attacks: Why H(secret + message) Is Broken

August 7, 2026 8 min read Haven Team

Suppose you want to prove a message came from you. A tempting first idea is to hash your secret key in front of the message and send the digest as a tag. It looks airtight, because nobody can reverse a hash to find your secret. The problem is that with the most common hash functions, an attacker who never learns your secret can still take your tag and forge a valid one for a longer message.


This is the length extension attack, and it is one of the cleaner lessons in cryptography because the flaw is not in the hash's collision resistance or its one-wayness. Those properties hold. The flaw is in how the hash is built internally, combined with a particular way people naively try to use it for authentication.

How the vulnerable hashes are built

MD5, SHA-1, SHA-256, and SHA-512 all use a design called the Merkle-Damgard construction. The message is split into fixed-size blocks, padded at the end to a block boundary, and fed one block at a time into a compression function. Each step mixes the next block into a running internal state. After the final block, that internal state is the digest you get back.

There is the whole problem in one sentence. The output of the hash is the complete internal state of the machine at the moment it stopped. Nothing is thrown away or finalized in a way that hides where it was.

The consequence

If a digest is the full internal state, then anyone holding a digest can load that state back into the algorithm and keep hashing more data, exactly as if they were continuing the original computation. They do not need to know what came before. The digest already captured it.

The attack, step by step

Say a server authenticates API requests with a tag computed as tag = SHA-256(secret || message), where || means concatenation and the secret is known only to the client and server. An attacker intercepts one legitimate request and sees both the message and its tag. They do not know the secret. Here is what they can still do.

  1. The attacker knows tag is the hash's internal state after processing secret || message || padding, where the padding is the standard scheme the hash appends to reach a block boundary.
  2. They load tag back into a SHA-256 engine as its starting state, which resumes the computation exactly where the server left off.
  3. They append their own chosen data, for example &admin=true, and let the hash keep running.
  4. The result is a valid tag for the message message || padding || &admin=true. The server, recomputing over its secret plus this new longer message, gets the same value and accepts it.

The attacker never learned the secret. They forged a tag for a message they chose, appended to the original, without ever knowing the key that was supposed to make forgery impossible. The one requirement is that they know or can guess the length of the secret, which is a small search at worst.

This is not just theory

In 2009, security researchers Thai Duong and Juliano Rizzo showed that the Flickr API used exactly this vulnerable construction to sign requests. By applying a length extension attack, they could forge valid API signatures and craft authenticated calls the developers never intended to allow. The same pattern has appeared in other web APIs that rolled their own signing scheme out of a bare hash. It is a recurring bug precisely because hash(secret || data) looks so reasonable to someone who has not met this attack.

The hash function did exactly what it promised. The mistake was assuming that a good hash function is automatically a good message authentication code. It is not.

The fixes, and why they work

There are three durable ways out, and they attack the problem from different angles.

Use HMAC instead of a bare hash

HMAC, the keyed-hash message authentication code, is the standard answer. Instead of hashing the key in front of the message once, it nests two hash operations with the key mixed into both an inner and an outer pass. The final output is a hash of a hash, so the internal state an attacker would want to extend is buried inside the outer call and never exposed. HMAC is provably resistant to length extension and is what you should reach for any time you need to authenticate data with a shared secret. We cover its structure in how HMAC works.

Use a hash that is not vulnerable

Not every hash uses Merkle-Damgard. SHA-3, based on the Keccak sponge construction, does not leak its full internal state as the digest, so it is not susceptible to length extension at all. The BLAKE2 and BLAKE3 families are likewise immune and include a built-in keyed mode designed for authentication. SHA-512/256, a truncated variant of SHA-512, also resists the attack because the truncation hides part of the state.

Change the construction

If you are stuck with a Merkle-Damgard hash and cannot use HMAC, hashing twice, as in H(H(secret || message)), defeats the extension because the attacker sees only the outer digest and cannot extend the inner one. This works, but it is a fragile pattern to hand-roll, and HMAC already exists to do the same job with a proof behind it.

The lesson that outlives the attack

The takeaway is not that SHA-256 is weak. It is excellent at the job it was designed for. The takeaway is that a cryptographic primitive has a specific contract, and using it outside that contract creates failures that look impossible from the outside. A hash guarantees collision resistance and preimage resistance. It does not guarantee that hash(secret || message) is unforgeable, because that was never a property it claimed.

This is why the standing advice in cryptographic engineering is to reach for the vetted construction rather than assemble your own from parts. HMAC, authenticated encryption, and the modern hash families were built by people who already met these attacks so you would not have to. The related lessons in nonce reuse and the cryptographic doom principle come from the same place: the primitive is rarely the weak point, the way it is wired together usually is.

Try Haven free for 15 days

Encrypted email and chat in one app. No credit card required.

Get Started →