# Chrome Cache Xss

> How to exploit Chrome's back/forward cache (bfcache) and disk cache interaction to achieve XSS. Use this skill whenever you're doing web pentesting, testing browser cache vulnerabilities, analyzing XSS vectors, or investigating client-side security issues involving navigation history, cached responses, or JSON rendering. Make sure to use this skill when the user mentions cache exploitation, bfcache, disk cache, browser navigation attacks, or wants to test how cached content can be rendered in unexpected contexts.

- Skill: `abelrguezr/chrome-cache-xss` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/chrome-cache-xss`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/chrome-cache-xss/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/chrome-cache-xss

---


# Chrome Cache to XSS Exploitation

This skill teaches you how to exploit the interaction between Chrome's **back/forward cache (bfcache)** and **disk cache** to achieve cross-site scripting (XSS) by forcing cached responses to render in the browser.

## Understanding the Cache Types

### Back/Forward Cache (bfcache)
- Stores a complete snapshot of a page including the JavaScript heap
- Prioritized over disk cache for back/forward navigations
- Provides faster restoration of page state

### Disk Cache
- Stores resources fetched from the web (including `fetch` requests)
- Does NOT include the JavaScript heap
- Used for back/forward navigations when bfcache is unavailable
- **Key vulnerability**: Cached responses can be rendered by the browser

## The Exploitation Technique

### Core Concept
The bfcache has precedence over the disk cache. To exploit disk cache behavior, you must **disable bfcache** first, forcing the browser to use disk cache for navigation.

### Disabling bfcache

**Method 1: Using `window.open()` with opener reference**
```javascript
// Open a new window/tab that maintains a reference to the opener
const newWindow = window.open('http://target-site.com/');
// The RelatedActiveContentsExist condition is now true
// This disables bfcache for the current page
```

**Method 2: Puppeteer (automated testing)**
Puppeteer disables bfcache by default, which aligns with Chromium's documentation conditions.

### Step-by-Step Exploitation

1. **Initial Setup**
   - Visit a target webpage (e.g., `https://example.com`)
   - Ensure you have a way to trigger the cache behavior

2. **Trigger Cache Storage**
   - Execute a request that will be cached:
   ```javascript
   // This request gets cached in disk cache
   fetch('http://target-site.com/api/token');
   // Even if it returns 500, the response is cached
   ```

3. **Navigate to Force Cache Usage**
   - Open a new tab/window with `window.open()` to disable bfcache
   - Navigate to the target page in the new tab
   - Use `history.back()` to trigger disk cache rendering

4. **Verify Cache Usage**
   - Open Chrome DevTools
   - Check the Network tab for cache indicators
   - Look for `(from disk cache)` in the Size column

### Practical Example

```javascript
// Step 1: Visit initial page
// User is at https://example.com

// Step 2: Make a request that will be cached
fetch('http://vulnerable-site.com/api/token')
  .then(response => {
    // Response is cached even if it's 500
    console.log('Request cached');
  });

// Step 3: Disable bfcache by opening new window
const newWindow = window.open('http://vulnerable-site.com/');

// Step 4: Navigate back to trigger disk cache
setTimeout(() => {
  newWindow.history.back();
  // Cached JSON response now renders on the page
}, 1000);
```

## Verification Methods

### Using Chrome DevTools
1. Open DevTools (F12)
2. Go to the **Network** tab
3. Check the **Size** column for `(from disk cache)`
4. Verify the response was served from cache

### Programmatic Verification
```javascript
// Check if response came from cache
fetch('http://target.com/api/token', { cache: 'default' })
  .then(response => {
    const headers = response.headers;
    // Look for cache-related headers
    console.log('Cache status:', headers.get('x-cache-status'));
  });
```

## When This Technique Works

- ✅ Target site uses `fetch` or XHR for API calls
- ✅ Responses are cacheable (appropriate Cache-Control headers)
- ✅ You can control navigation (history.back/forward)
- ✅ bfcache can be disabled (via window.open or other methods)
- ❌ Site uses `no-store` or `no-cache` headers
- ❌ Responses are not cacheable by design
- ❌ Modern browsers with aggressive cache policies

## Security Implications

### What This Enables
- **XSS via cached content**: Cached JSON/HTML can be rendered in unexpected contexts
- **Information disclosure**: Sensitive data in cached responses may be exposed
- **Session manipulation**: Cached tokens or session data can be exploited

### Mitigation Strategies
1. **Cache-Control Headers**: Use `no-store` for sensitive responses
2. **Content-Type Validation**: Ensure responses aren't rendered as HTML
3. **Navigation Controls**: Limit history manipulation capabilities
4. **Response Validation**: Verify response context before rendering

## Testing Checklist

- [ ] Identify cacheable endpoints on target
- [ ] Verify bfcache can be disabled
- [ ] Test disk cache behavior with DevTools
- [ ] Attempt to render cached responses
- [ ] Check for XSS vectors in cached content
- [ ] Document findings and reproduction steps

## References

- [web.dev on bfcache](https://web.dev/i18n/en/bfcache/)
- [Chromium Disk Cache Design](https://www.chromium.org/developers/design-documents/network-stack/disk-cache/)
- [Original Writeup](https://blog.arkark.dev/2022/11/18/seccon-en/#web-spanote)

## Related Techniques

- **Cache Poisoning**: Manipulating cache to serve malicious content
- **History Manipulation**: Using history API for navigation attacks
- **JSONP Exploitation**: Leveraging JSON responses for XSS
- **Content-Type Confusion**: Forcing browsers to render data as HTML

