BREACH sounds like the name of a grim sci-fi movie, but it is really a very practical web attack with a deeply annoying personality. It targets something most developers turn on for good reasons: HTTP compression. Gzip and Brotli make pages smaller, faster, and cheaper to deliver. Lovely. BREACH asks a rude question: what if that same compression feature can help an attacker guess secrets hidden inside a page, one tiny clue at a time?
That is exactly the trick. The BREACH attack is a compression side-channel attack against HTTPS responses. It does not break TLS encryption like a cartoon burglar with a crowbar. It abuses the fact that compressed responses get slightly shorter when repeated text matches well. If an attacker can inject text into a request and then measure the size of the compressed response over and over, they can slowly recover secrets such as CSRF tokens, password reset tokens, email addresses, or other hidden values.
Yes. Really. Your site can be encrypted, use modern TLS, and still leak information because compression is basically trying to be helpful at exactly the wrong moment.

What Is BREACH, in Plain English?
BREACH stands for Browser Reconnaissance and Exfiltration via Adaptive Compression of Hypertext. That name is doing entirely too much, so let us translate it into human language.
Imagine you own a suitcase company. To save space, you use vacuum bags. When two fluffy sweaters overlap nicely, the bag shrinks more. An attacker does not get to open the bag, but they can weigh it. If they keep slipping in test items and the bag suddenly gets lighter, they learn which guess matched something already inside.
That is BREACH. The suitcase is the compressed HTTP response. The fluffy sweater already inside is the secret, like a CSRF token. The attacker-controlled test item is input reflected in the page, like a search query, error message, or autocomplete parameter. The only thing the attacker really needs is a way to trigger lots of requests and observe how big the encrypted responses are.
The important part is this: BREACH is not about breaking encryption directly. TLS can be perfectly fine. The leak comes from response size.
How Does a BREACH Attack Work?
A BREACH attack usually needs four ingredients:
- The victim is logged in, or the response contains a secret tied to that user session.
- The application reflects attacker-controlled input somewhere in the same response.
- The response is compressed with gzip, Brotli, or another content compression method.
- The attacker can trigger many requests and measure response sizes.
When those pieces line up, the attack becomes a weird guessing game.
Step 1: A secret sits inside the HTML
A classic example is an authenticated page containing a hidden CSRF token:
<input type="hidden" name="csrf" value="r9Gk3LxV...">
The token is there for a good reason. It helps stop forged form submissions. The trouble starts when the page also reflects user input, like:
<p>You searched for: BRE...</p>
If the attacker can control the search text, they can keep trying prefixes that may match the secret token. When the guess overlaps with the hidden token, compression works a little better and the response gets a little smaller.
Step 2: The attacker keeps probing
The attacker lures the victim to a malicious page and causes the browser to send many requests to the target site. Each request contains a slightly different guess. The browser includes the victim’s cookies automatically if the conditions allow it, so the target site returns the logged-in page with the real secret embedded.
The attacker cannot necessarily read the response body because of the same-origin policy. But they do not need the body. They only need the size. If the guess makes compression slightly more efficient, the encrypted payload becomes slightly shorter. That tiny difference is the clue.
Step 3: One byte at a time
By repeating the request many times and comparing lengths, the attacker can learn the secret character by character. It is slow, fussy, and data-hungry. It is also very real. Side-channel attacks often look silly until you realize they are basically statistics wearing a ski mask.
Step 4: The attacker uses the stolen secret
Once a CSRF token or similar secret is recovered, the attacker can use it to bypass the very control that secret was supposed to provide. That is the part people find offensive, and honestly, fair enough. You added the token for protection. Compression turns it into a hint system.
Why HTTPS Does Not Save You Here
This is the part that feels unfair. Everyone learns that HTTPS protects confidentiality in transit. That is true. But HTTPS hides the content, not the fact that one encrypted response is 12,438 bytes and another is 12,431 bytes.
BREACH lives in that difference.
Think of it like someone cannot hear your whole conversation through a wall, but they can hear when the room goes silent, when everybody laughs, and when someone drops a plate. Metadata leaks are still leaks. Compression side channels are metadata leaks with a postgraduate degree.
This is also why turning off TLS is not a mitigation. That would be like fixing a squeaky brake by setting the car on fire.
BREACH vs CRIME vs HEIST: Same Family, Different Tricks
Security people love naming attacks like failed metal bands, so here is the quick family tree:
CRIME targeted TLS or SPDY compression. That one became far less practical once TLS-level compression was disabled almost everywhere.
BREACH targets HTTP response body compression. That matters because gzip and Brotli are still widely used for good performance reasons.
HEIST and related browser-side techniques showed that attackers may not even need a classic network vantage point if the browser can help reveal timing or size information.
The lesson is simple: if secrets and attacker input share the same compressed output, you should assume clever people will try to turn that into an oracle.
Why Padding Is Usually False Security
Padding sounds smart at first. If response sizes leak information, just add random bytes so the sizes become noisy. Problem solved, right?
Not really. Padding is usually false security because it treats the symptom, not the cause.
Random noise can be averaged out
If an attacker can make thousands of requests, random padding becomes background fuzz. The attack signal does not disappear. It just takes more samples. Given enough tries, averages smooth out the noise and the size differences become useful again.
Fixed padding is basically decorative
If you always add the same amount of padding, you have done almost nothing. Every response is still comparable to every other response. You have just made them all bigger, which is a very expensive way to achieve very little.
Developers overestimate it
This is the dangerous part. Once padding is enabled, teams feel protected and move on. Meanwhile, the real vulnerability remains: a secret and attacker-controlled reflection still live in the same compressed response.
Padding rarely lands exactly where it matters
To be effective, padding must be unpredictable, carefully sized, consistently applied, and hard for the attacker to model. In practice, implementations are uneven. One template adds it, another does not. One response path compresses before padding. Another pads before rendering. Suddenly your safety blanket has holes in it and is also on fire.
Padding can make exploitation harder. That is fine as a secondary friction control. It is not a trustworthy primary defense.
What Can BREACH Leak?
The headline example is the CSRF token, because it is often embedded directly into forms and pages. But the attack is not married to CSRF. Any secret present in a compressible response can become a target, including:
- CSRF tokens
- password reset tokens
- email addresses or partial PII
- session-bound anti-abuse tokens
- OAuth state values or one-time nonces
- API keys or internal identifiers accidentally rendered into templates
If it is secret, stable enough to guess incrementally, and appears beside attacker-controlled input in a compressed response, it belongs on your threat model.
How to Prevent BREACH Properly
This is where we stop admiring the problem and start acting like adults.
1. Disable compression on sensitive dynamic responses
The most direct mitigation is to turn off gzip and Brotli for responses that contain secrets and reflect input. Login forms, account pages, search pages for authenticated users, password reset flows, settings forms, and admin panels are common candidates.
For NGINX or Angie, that usually means being selective instead of going nuclear. You do not need to disable compression for your entire website. Static assets and public pages can usually stay compressed. Sensitive authenticated HTML is where you should be cautious.
location /account/ {
gzip off;
brotli off;
}
location /wp-admin/ {
gzip off;
brotli off;
}
If you are already tuning compression with NGINX or Angie, the broader context is covered in our comparison of Brotli, zstd, and zlib-ng compression.
2. Stop reflecting attacker-controlled input next to secrets
This is one of the best fixes because it removes the oracle. If a page contains a CSRF token, do not also echo user-controlled query parameters, search terms, or other reflected data into the same compressed template unless you absolutely have to.
Separate those concerns. Put the search UI on a different response. Move live reflection to a public endpoint. Rework templates so secrets are not sitting right beside attacker-controlled bytes. That is less glamorous than buying a new WAF module, but it is often more effective.
3. Use CSRF defenses that do not create a stable compression target
Yes, you still need CSRF protection. No, plain old hidden tokens dumped into every compressed page are not enough by themselves.
Safer patterns include:
- Per-request or masked CSRF tokens so the exposed value changes every time and becomes harder to recover usefully.
- Synchronizer tokens combined with careful placement so they are not reflected in compressible responses with attacker input.
- Double-submit cookie patterns when appropriate, with strong cookie flags and validation.
The point is not “remove CSRF protection.” The point is “do not make your CSRF token a reusable compression oracle.”
4. Enforce SameSite cookies
Cookies marked SameSite=Lax or SameSite=Strict can reduce the browser’s willingness to send authenticated cookies on cross-site requests. That matters because BREACH often depends on the victim browser making credentialed requests from an attacker-controlled origin.
This is not a complete BREACH fix, but it meaningfully reduces the attack surface and helps with ordinary CSRF too. In other words, it is one of those rare security settings that is both boring and useful, which is basically the dream.
5. Validate Origin and Referer headers
For state-changing requests, validate the Origin header where possible and fall back carefully to Referer checks when necessary. This is not perfect, but it raises the bar for cross-site abuse and complements token-based defenses.
If your application accepts dangerous actions purely because a hidden field matched, you are trusting a single layer. BREACH loves single layers.
6. Rate-limit suspicious repeated requests
BREACH needs many measurements. That makes rate limiting, anomaly detection, and bot friction useful as supporting controls. If one page is being hit with thousands of tiny variant requests, that is worth noticing.
On the web-server side, you can combine app logic with controls such as ModSecurity or request throttling. If you are already hardening a WordPress or NGINX stack, our ModSecurity and OWASP CRS guide and our WordPress hardening write-up cover broader request filtering patterns that help here too.
7. Keep secrets out of compressible HTML when possible
If a secret does not need to be in the page, do not put it there. Move it server-side. Use headers or dedicated non-compressed endpoints where appropriate. Revisit whether the template genuinely needs to render the secret at all. A shocking amount of “required” template data turns out to be legacy furniture nobody has questioned since 2019.
8. Segment public and authenticated experiences
Public pages can be aggressively cached and compressed. Authenticated pages deserve stricter handling. If you are serving WordPress through NGINX or Angie, this split is already a good idea for performance and security reasons. The same architecture that improves cache hit rate also makes it easier to disable compression where secrets live.
That broader setup work is discussed in our WordPress on NGINX and PHP-FPM guide and in our reverse proxy configuration article.
What Not to Do
- Do not assume HTTPS alone solves BREACH.
- Do not keep secrets and attacker reflection in the same compressed response just because the page “works fine.”
- Do not rely on random padding as the main mitigation.
- Do not disable all compression everywhere unless you have no better option. Be selective and deliberate.
- Do not treat CSRF tokens as magical objects. They are effective only when the surrounding design is sound.
A Practical BREACH Defense Checklist
- Inventory pages that contain secrets and user-controlled reflection.
- Disable gzip and Brotli on those sensitive responses.
- Mask or rotate CSRF tokens so they are not stable reusable targets.
- Enable
SameSite,Secure, andHttpOnlyon cookies. - Validate
Originand, where needed,Refererfor state-changing requests. - Rate-limit repeated probing patterns.
- Keep public compressed content separate from authenticated secret-bearing content.
- Review templates for needless reflection of attacker-controlled input.
That list is less sexy than saying “we added padding.” It is also much more likely to protect you.
Why This Still Matters in 2026
Because performance tuning and security tuning keep colliding in the same hallway.
Everyone wants smaller responses, faster pages, lower bandwidth, and greener hosting bills. That is why compression is everywhere. Modern stacks also keep pushing more state, more personalization, and more tokens into dynamic HTML. That is why side channels keep finding room to breathe.
BREACH is not the only compression leak on Earth, but it is the perfect reminder that a feature can be correct, useful, and still dangerous in the wrong context. Compression is not bad. Reflecting secrets and attacker-controlled input into the same compressed response is bad. There is the villain. Not the vacuum bag. The packing choices.
Frequently Asked Questions
What is the BREACH attack in one sentence?
BREACH is an attack that uses differences in compressed HTTPS response sizes to help an attacker guess secrets such as CSRF tokens or reset tokens.
Does BREACH mean I should disable gzip or Brotli everywhere?
No. The practical fix is to disable compression selectively on sensitive dynamic pages that contain secrets and attacker-controlled reflection. Public assets and ordinary static content can usually stay compressed.
Why are CSRF tokens involved so often?
Because CSRF tokens are often embedded directly into HTML forms and remain stable long enough to be guessed. If they appear in a compressed response next to attacker-controlled input, they can become a BREACH target.
Is random padding a good BREACH mitigation?
Only as a minor supporting friction control. Padding adds noise, but attackers can often average that noise out with enough samples. It should not be your main defense.
Can SameSite cookies help prevent BREACH?
They help reduce the browser’s willingness to send authenticated cookies on cross-site requests, which can make BREACH-style probing harder. They are useful, but they do not replace careful compression and template design.
Is BREACH only a WordPress problem?
No. Any web application can be affected if it compresses responses that contain secrets and attacker-controlled reflection. WordPress, custom PHP apps, Python frameworks, Node.js apps, and Java stacks can all make the same mistake.
Related Posts
- How to Install ModSecurity and OWASP CRS on NGINX – A practical guide to adding request filtering and defensive friction at the web-server layer.
- WordPress Hardening Plugin for ModSecurity CRS – A broader hardening strategy for blocking abusive traffic before it reaches your PHP code.
- NGINX zstd vs Brotli vs zlib-ng Compression – Useful background if you are tuning compression and want to understand what to disable where.
- WordPress NGINX Configuration: PHP-FPM Tuning, FastCGI Cache and Redis – Covers the architectural split between public cached traffic and authenticated dynamic traffic.