Caido Mode Skill
Overview
Full-coverage CLI for Caido's API, built on the official @caido/sdk-client package. Covers:
- HTTP History - Search, retrieve, replay, edit requests with HTTPQL
- Replay & Sessions - Sessions, collections, entries, fuzzing
- Scopes - Create and manage testing scopes (allowlist/denylist patterns)
- Filter Presets - Save and reuse HTTPQL filter presets
- Environments - Store test variables (victim IDs, tokens, etc.)
- Findings - Create, list, update security findings
- Tasks - Monitor and cancel background tasks
- Projects - Switch between testing projects
- Hosted Files - Manage files served by Caido
- Intercept - Enable/disable request interception programmatically
- Plugins - List installed plugins
- Export - Convert requests to curl commands for PoCs
- Health - Check Caido instance status
All traffic goes through Caido, so it appears in the UI for further analysis.
Why This Model?
Cookies and auth tokens can be huge - session cookies, JWTs, CSRF tokens can easily be 1-2KB. Rather than manually copy-pasting:
- Find an organic request in Caido's HTTP history that already has valid auth
- Use
editto modify just what you need (path, method, body) while keeping all auth headers intact - Send it - response comes back with full context preserved
Authentication Setup
Setup (One-Time)
- Open Dashboard → Developer → Personal Access Tokens
- Create a new token
- Run:
npx tsx ~/.agents/skills/caido-mode/caido-client.ts setup <your-pat>
# Non-default Caido instance
npx tsx ~/.agents/skills/caido-mode/caido-client.ts setup <pat> http://192.168.1.100:8080
# Or set env var instead
export CAIDO_PAT=caido_xxxxx
The setup command validates the PAT via the SDK (which exchanges it for an access token), then saves both the PAT and the cached access token to ~/.agents/config/secrets.json. Subsequent runs load the cached token directly, and a valid cached token can be used even when the PAT is absent.
Check Status
npx tsx ~/.agents/skills/caido-mode/caido-client.ts auth-status
How Auth Works
The SDK uses a device code flow internally — the PAT auto-approves it and receives an access token + refresh token. A custom SecretsTokenCache (implementing the SDK's TokenCache interface) persists these tokens to secrets.json so they survive across CLI invocations.
Auth resolution: CAIDO_PAT env var → ~/.agents/config/secrets.json PAT → valid cached access token → error with setup instructions
CLI Tool
Located at ~/.agents/skills/caido-mode/caido-client.ts. All commands output JSON.
HTTP History & Testing Commands
search - Search HTTP history with HTTPQL
npx tsx caido-client.ts search 'req.method.eq:"POST" AND resp.code.eq:200'
npx tsx caido-client.ts search 'req.host.cont:"api"' --limit 50
npx tsx caido-client.ts search 'req.host.cont:"api"' --desc --limit 10
npx tsx caido-client.ts search 'req.path.cont:"/admin"' --ids-only
npx tsx caido-client.ts search 'resp.raw.cont:"password"' --after <cursor>
recent - Get recent requests
npx tsx caido-client.ts recent
npx tsx caido-client.ts recent --limit 50
get / get-response - Retrieve full details
npx tsx caido-client.ts get <request-id>
npx tsx caido-client.ts get <request-id> --headers-only
npx tsx caido-client.ts get-response <request-id>
npx tsx caido-client.ts get-response <request-id> --compact
edit - Edit and replay (KEY FEATURE)
Modifies an existing request while preserving all cookies/auth headers:
# Change path (IDOR testing)
npx tsx caido-client.ts edit <id> --path /api/user/999
# Change method and add body
npx tsx caido-client.ts edit <id> --method POST --body '{"admin":true}'
# Add/remove headers
npx tsx caido-client.ts edit <id> --set-header "X-Forwarded-For: 127.0.0.1"
npx tsx caido-client.ts edit <id> --remove-header "X-CSRF-Token"
# Find/replace text anywhere in request
npx tsx caido-client.ts edit <id> --replace "user123:::user456"
# Combine multiple edits
npx tsx caido-client.ts edit <id> --method PUT --path /api/admin --body '{"role":"admin"}' --compact
# Reuse an existing replay tab/session for repeated probes
npx tsx caido-client.ts edit <id> --path /api/user/1001 --session <session-id> --compact
| Option | Description |
|---|---|
--method <METHOD> | Change HTTP method |
--path <path> | Change request path |
--set-header <Name: Value> | Add or replace a header (repeatable) |
--remove-header <Name> | Remove a header (repeatable) |
--body <content> | Set request body (auto-updates Content-Length) |
--replace <from>:::<to> | Find/replace text anywhere in request (repeatable) |
--session <id> | Reuse an existing replay session instead of creating a new tab |
--collection <id> | Put a newly created replay session in a collection |
--sni <host> | Override TLS SNI |
--connect-host <host> | Connect to a different host while preserving the HTTP request |
--connect-port <port> | Connect to a different port |
--connect-tls / --connect-no-tls | Force TLS/plaintext for the connection |
replay / send-raw - Send requests
# Replay as-is
npx tsx caido-client.ts replay <request-id>
# Replay with custom raw
npx tsx caido-client.ts replay <id> --raw "GET /modified HTTP/1.1\r\nHost: example.com\r\n\r\n"
# Send completely custom request
npx tsx caido-client.ts send-raw --host example.com --port 443 --tls --raw "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
npx tsx caido-client.ts send-raw --host example.com --raw @request.txt --name "G /"
cat request.txt | npx tsx caido-client.ts send-raw --host example.com --raw -
# Connect elsewhere while preserving the request Host/SNI you need
npx tsx caido-client.ts replay <id> --connect-host 10.0.0.5 --connect-port 8443 --sni example.com
--raw accepts a string with \r\n escapes, @file to read from disk, or - to read from stdin.
export-curl - Convert to curl for PoCs
npx tsx caido-client.ts export-curl <request-id>
Outputs a ready-to-use curl command with all headers and body.
Replay Tab Lookup
Use these when a Caido replay tab is already open and you want to work from its active entry directly.
npx tsx caido-client.ts get-session <session-id-or-name> --compact
npx tsx caido-client.ts replay-entries <session-id-or-name> --limit 20
npx tsx caido-client.ts replay-entries <session-id-or-name> --raw --compact
npx tsx caido-client.ts edit-session <session-id-or-name> --body '{"test":true}' --compact
session-entries is accepted as an alias for replay-entries.
Replay Sessions & Collections
Sessions
# Create replay session from an existing request
npx tsx caido-client.ts create-session <request-id>
npx tsx caido-client.ts create-session <request-id> --collection <collection-id>
# ALWAYS rename sessions for easy identification in Caido UI
npx tsx caido-client.ts rename-session <session-id> "idor-user-profile"
# List all replay sessions
npx tsx caido-client.ts replay-sessions
npx tsx caido-client.ts replay-sessions --limit 50
# Move sessions between collections
npx tsx caido-client.ts move-session <session-id> <collection-id>
# Delete replay sessions
npx tsx caido-client.ts delete-sessions <session-id-1>,<session-id-2>
Collections
Organize replay sessions into collections:
# List replay collections
npx tsx caido-client.ts replay-collections
npx tsx caido-client.ts replay-collections --limit 50
# Create a collection
npx tsx caido-client.ts create-collection "IDOR Testing"
# Rename a collection
npx tsx caido-client.ts rename-collection <collection-id> "Auth Bypass Tests"
# Delete a collection
npx tsx caido-client.ts delete-collection <collection-id>
Fuzzing
# Create automate session for fuzzing
npx tsx caido-client.ts create-automate-session <request-id>
# Start fuzzing (configure payloads and markers in Caido UI first)
npx tsx caido-client.ts fuzz <session-id>
Scope Management
Define what's in scope for your testing. Uses glob patterns.
# List all scopes
npx tsx caido-client.ts scopes
# Create scope with allowlist and denylist
npx tsx caido-client.ts create-scope "Target Corp" --allow "*.target.com,*.target.io" --deny "*.cdn.target.com"
# Update scope
npx tsx caido-client.ts update-scope <scope-id> --allow "*.target.com,*.api.target.com"
# Delete scope
npx tsx caido-client.ts delete-scope <scope-id>
Glob patterns: *.example.com matches any subdomain of example.com.
Filter Presets
Save frequently used HTTPQL queries as named presets.
# List saved filters
npx tsx caido-client.ts filters
# Create filter preset
npx tsx caido-client.ts create-filter "API Errors" --query 'req.path.cont:"/api/" AND resp.code.gte:400'
npx tsx caido-client.ts create-filter "Auth Endpoints" --query 'req.path.regex:"/(login|auth|oauth)/"' --alias "auth"
# Update filter
npx tsx caido-client.ts update-filter <filter-id> --query 'req.path.cont:"/api/" AND resp.code.gte:500'
# Delete filter
npx tsx caido-client.ts delete-filter <filter-id>
Environment Variables
Store testing variables that persist across sessions. Great for IDOR testing with multiple user IDs.
# List environments
npx tsx caido-client.ts envs
# Create environment
npx tsx caido-client.ts create-env "IDOR-Test"
# Set variables
npx tsx caido-client.ts env-set <env-id> victim_user_id "user_456"
npx tsx caido-client.ts env-set <env-id> attacker_token "eyJhbG..."
# Select active environment
npx tsx caido-client.ts select-env <env-id>
# Deselect environment
npx tsx caido-client.ts select-env
# Delete environment
npx tsx caido-client.ts delete-env <env-id>
Findings
Create, list, and update security findings. Shows up in Caido's Findings tab.
# List all findings
npx tsx caido-client.ts findings
npx tsx caido-client.ts findings --limit 50
# Get a specific finding
npx tsx caido-client.ts get-finding <finding-id>
# Create finding linked to a request
npx tsx caido-client.ts create-finding <request-id> \
--title "IDOR in user profile endpoint" \
--description "Can access other users' profiles by changing ID parameter" \
--reporter "rez0"
# With deduplication key (prevents duplicates)
npx tsx caido-client.ts create-finding <request-id> \
--title "Auth bypass on /admin" \
--dedupe-key "admin-auth-bypass"
# Update finding
npx tsx caido-client.ts update-finding <finding-id> \
--title "Updated title" \
--description "Updated description"
Tasks
Monitor and cancel background tasks (imports, exports, etc.).
# List all tasks
npx tsx caido-client.ts tasks
# Cancel a running task
npx tsx caido-client.ts cancel-task <task-id>
Project Management
# List all projects
npx tsx caido-client.ts projects
# Switch active project
npx tsx caido-client.ts select-project <project-id>
Hosted Files
# List hosted files
npx tsx caido-client.ts hosted-files
# Delete hosted file
npx tsx caido-client.ts delete-hosted-file <file-id>
Intercept Control
# Check intercept status
npx tsx caido-client.ts intercept-status
# Enable/disable interception
npx tsx caido-client.ts intercept-enable
npx tsx caido-client.ts intercept-disable
Info, Health & Plugins
# Current user info
npx tsx caido-client.ts viewer
# List installed plugins
npx tsx caido-client.ts plugins
# Check Caido instance health (version, ready state)
npx tsx caido-client.ts health
Output Control
Works with get, get-response, replay, edit, send-raw:
| Flag | Description |
|---|---|
--max-body <n> | Max response body lines (default: 200, 0=unlimited) |
--max-body-chars <n> | Max body chars (default: 5000, 0=unlimited) |
--no-request | Skip request raw in output |
--headers-only | Only HTTP headers, no body |
--compact | Shorthand: --no-request --max-body 50 --max-body-chars 5000 |
HTTPQL Reference
Caido's query language for searching HTTP history.
CRITICAL: String values MUST be quoted. Integer values are NOT quoted.
CRITICAL: HTTPQL has NO NOT operator. Never write NOT expr. Use the negated operator variant instead:
ncont(not contains),nlike(not like),nregex(not regex),ne(not equals)- Wrong:
NOT req.path.cont:"/admin" - Right:
req.path.ncont:"/admin"
Namespaces and Fields
| Namespace | Field | Type | Description |
|---|---|---|---|
req | ext | string | File extension (includes .) |
req | host | string | Hostname |
req | method | string | HTTP method (uppercase) |
req | path | string | URL path |
req | query | string | Query string |
req | raw | string | Full raw request |
req | port | int | Port number |
req | len | int | Request body length |
req | created_at | date | Creation timestamp |
req | tls | bool | Is HTTPS |
resp | raw | string | Full raw response |
resp | code | int | Status code |
resp | len | int | Response body length |
resp | roundtrip | int | Roundtrip time (ms) |
row | id | int | Request ID |
source | - | special | "intercept", "replay", "automate", "workflow" |
preset | - | special | Filter preset reference |
Operators
String: eq, ne, cont, ncont, like, nlike, regex, nregex
Integer: eq, ne, gt, gte, lt, lte
Boolean: eq, ne
Logical: AND, OR, parentheses for grouping
Example Queries
# POST requests with 200 responses
req.method.eq:"POST" AND resp.code.eq:200
# API requests
req.host.cont:"api" OR req.path.cont:"/api/"
# Standalone string searches both req and resp
"password" OR "secret" OR "api_key"
# Error responses
resp.code.gte:400 AND resp.code.lt:500
# Large responses (potential data exposure)
resp.len.gt:100000
# Slow endpoints
resp.roundtrip.gt:5000
# Auth endpoints by regex
req.path.regex:"/(login|auth|signin|oauth)/"
# Replay/automate traffic only
source:"replay" OR source:"automate"
# Date filtering
req.created_at.gt:"2024-01-01T00:00:00Z"
# Exclude paths (use ncont, NOT doesn't exist)
req.path.ncont:"/static"
# Not equal
req.method.ne:"OPTIONS"
# Combine negations
req.path.ncont:"/health" AND req.path.ncont:"/metrics"
SDK Architecture
This CLI is built on @caido/sdk-client v0.2.0+, using a clean multi-file architecture:
caido-client.ts # CLI entry point — arg parsing + command dispatch
lib/
client.ts # SDK Client singleton, SecretsTokenCache, auth config
graphql.ts # gql documents for features not yet in SDK
output.ts # Output formatting (truncation, headers-only, raw→curl)
types.ts # Shared types (OutputOpts)
commands/
requests.ts # search, recent, get, get-response, export-curl
replay.ts # replay, send-raw, edit, replay-tab lookup, sessions, collections, automate, fuzz
findings.ts # findings, get-finding, create-finding, update-finding
management.ts # scopes, filters, environments, projects, hosted-files, tasks
intercept.ts # intercept-status, intercept-enable, intercept-disable
info.ts # viewer, plugins, health, setup, auth-status
SDK Coverage
Most features use the high-level SDK directly:
| SDK Method | Commands |
|---|---|
client.request.list(), .get() | search, recent, get, get-response, export-curl |
client.replay.sessions.* | create-session, replay-sessions, rename-session, delete-sessions |
client.replay.collections.* | replay-collections, create-collection, rename-collection, delete-collection |
client.replay.send() | replay, send-raw, edit |
client.finding.* | findings, get-finding, create-finding, update-finding |
client.scope.* | scopes, create-scope, update-scope, delete-scope |
client.filter.* | filters, create-filter, update-filter, delete-filter |
client.environment.* | envs, create-env, select-env, env-set, delete-env |
client.project.* | projects, select-project |
client.hostedFile.* | hosted-files, delete-hosted-file |
client.task.* | tasks, cancel-task |
client.user.viewer() | viewer |
client.health() | health |
Features not yet in the high-level SDK use client.graphql.query()/client.graphql.mutation() with gql tagged templates from graphql-tag. This is the proper SDK approach (typed documents through urql) — no raw fetch anywhere.
| GraphQL Document | Commands |
|---|---|
INTERCEPT_OPTIONS_QUERY | intercept-status |
PAUSE_INTERCEPT / RESUME_INTERCEPT | intercept-enable, intercept-disable |
PLUGIN_PACKAGES_QUERY | plugins |
CREATE_AUTOMATE_SESSION | create-automate-session |
GET_AUTOMATE_SESSION | fuzz (verify session) |
START_AUTOMATE_TASK | fuzz (start task) |
Workflow Examples
1. IDOR Testing (Primary Pattern)
# Find authenticated request
npx tsx caido-client.ts search 'req.path.cont:"/api/user"' --limit 10
# Create scope
npx tsx caido-client.ts create-scope "IDOR-Test" --allow "*.target.com"
# Create environment for test data
npx tsx caido-client.ts create-env "IDOR-Test"
npx tsx caido-client.ts env-set <env-id> victim_id "user_999"
# Test IDOR by changing user ID
npx tsx caido-client.ts edit <request-id> --path /api/user/999
# Mark as finding if it works
npx tsx caido-client.ts create-finding <request-id> --title "IDOR on /api/user/:id"
# Export curl for PoC
npx tsx caido-client.ts export-curl <request-id>
2. Privilege Escalation Testing
npx tsx caido-client.ts search 'req.path.cont:"/admin"' --limit 10
npx tsx caido-client.ts edit <id> --path /api/admin/users --method GET
npx tsx caido-client.ts edit <id> --method POST --body '{"role":"admin"}'
3. Header Bypass Testing
npx tsx caido-client.ts edit <id> --set-header "X-Forwarded-For: 127.0.0.1"
npx tsx caido-client.ts edit <id> --set-header "X-Original-URL: /admin"
npx tsx caido-client.ts edit <id> --remove-header "X-CSRF-Token"
4. Fuzzing with Automate
npx tsx caido-client.ts create-automate-session <request-id>
# Configure payload markers and wordlists in Caido UI
npx tsx caido-client.ts fuzz <session-id>
5. Filter + Analyze Pattern
# Save useful filters
npx tsx caido-client.ts create-filter "API 4xx" --query 'req.path.cont:"/api/" AND resp.code.gte:400 AND resp.code.lt:500'
npx tsx caido-client.ts create-filter "Large Responses" --query 'resp.len.gt:100000'
npx tsx caido-client.ts create-filter "Sensitive Data" --query '"password" OR "secret" OR "api_key" OR "token"'
# Quick search using preset alias
npx tsx caido-client.ts search 'preset:"API 4xx"' --limit 20
MCP Server Tools (caido-mcp-server)
When connected via opencode's MCP server (caido-mcp-server fork at Aceproulx/caido-mcp-server), these tools are available directly:
caido_send_request
Sends a raw HTTP request via Caido's replay system. The full request/response is returned inline.
{
"raw": "POST /api/login HTTP/1.1\r\nHost: target.com\r\nContent-Type: application/json\r\nContent-Length: 39\r\n\r\n{\"username\":\"admin\",\"password\":\"test\"}",
"host": "target.com",
"sessionId": "optional-previous-session-id"
}
Key details:
sessionIdis auto-managed if omitted (creates a fresh session), but you can pass the returnedsessionIdto chain multiple requests in the same session- Cookie jar is enabled by default —
Set-Cookiefrom responses auto-injects into the next request on the same session - Pass
setCookies: {"CookieName": "new-value"}to override specific cookies mid-session without clearing the jar - Pass
useCookieJar: falseto disable jar for a single call - No header redaction by default — all header values (Authorization, Cookie, etc.) are visible in output. Redact with
CAIDO_REDACT_HEADERS=trueenv var - Response diff tracks repeated identical responses via body hash (output includes
difffield when same response repeats) - Pools up to 10s; on timeout returns
entryIdfor follow-up viacaido_get_replay_entry
caido_get_replay_entry
Retrieve a specific replay entry's request + response by entry ID or by session.
caido_export_curl
Convert a request to a curl command (handy for PoCs). Works by request ID.
caido_get_session_cookies
List cookies stored in the session jar for a given URL. Cookie values are returned (not just names).
caido_clear_session_cookies
Wipe the session jar between test runs.
Batch & Race Window Tools
caido_batch_send— Send multiple requests concurrentlycaido_race_window_send— Race-condition style parallel sends
Workflow: Send a request with body via MCP tools
caido_send_request with:
raw: "POST /path HTTP/1.1\r\nHost: target.com\r\nContent-Type: application/json\r\nContent-Length: {len}\r\nConnection: close\r\n\r\n{body}"
host: "target.com"
The MCP server handles the Caido replay flow internally (create session → start task → update draft → start replay task → poll for response).
Instructions for Claude
- PREFER
caido_send_requestOVERedit/replaywhen using MCP tools — it handles cookie jar, session management, and response polling automatically - Workflow: Use
caido_send_requestto probe endpoints. Chain requests by reusing the returnedsessionIdto maintain auth - Don't dump raw requests into context - use
--compactwhen using the CLI client - Always check auth first: Try a probe request first; check if the response reflects auth state
- ALWAYS NAME REPLAY TABS: When using CLI,
rename-session <id> "idor-user-profile" - Create findings for anything interesting - they show up in Caido's Findings tab
- Use
caido_export_curlwhen building PoCs for reports - For body requests: Include
Content-Lengthmatching the actual body size. UseConnection: closeto avoid keep-alive complications - Cookie overrides: Use
setCookiesparam to swap auth tokens mid-session:setCookies: {"session": "attacker-token"} - Output is JSON - parse response fields as needed
- NEVER use
NOTin HTTPQL - it doesn't exist. Use negated operators:ne,ncont,nlike,nregex - Headers are NOT redacted — all header values (Authorization, Cookie, Set-Cookie, API keys) are visible in tool output. If you need redaction, set env var
CAIDO_REDACT_HEADERS=trueon the MCP server
Performance & Context Optimization
search/recentomitrawfield (~200 bytes per request, safe for 100+)getfetchesraw(~5-20KB per request, fetch only what you need)- Use
--limitaggressively (start with 5-10) - Use
--compactflag for quick exploration - Filter server-side with HTTPQL, not client-side
Error Handling
- Auth errors (caido-client CLI): Run
npx tsx ~/.agents/skills/caido-mode/caido-client.ts auth-statusto check, re-setup withnpx tsx ~/.agents/skills/caido-mode/caido-client.ts setup <pat> - Auth errors (MCP server): Tokens stored at
~/.caido-mcp/token.json. Re-auth:cd /home/aceos/caido-mcp-server && ./caido-mcp-server login --url http://127.0.0.1:8081 - Connection refused: Caido not running →
npx tsx caido-client.ts health - InstanceNotReadyError: Caido is starting up, wait and retry
Related Skills
caido-plugin-dev- For building Caido plugins (backend + frontend)spider- Crawling with Katana (uses Caido as proxy)website-fuzzing- Remote ffuf fuzzing on hunt6JsAnalyzer- JS analysis for traffic-discovered filesbug-hunting- Main-app focused bug hunting workflow; uses Caido MCP tools for request replay and analysisbug-validator- Adversarial validation pass for security findings; re-tests via Caido replay
MCP Server Config
The forked caido-mcp-server is configured in ~/.config/opencode/opencode.json:
{
"mcp": {
"caido": {
"type": "local",
"command": ["/home/aceos/caido-mcp-server/caido-mcp-server", "serve"],
"enabled": true,
"environment": { "CAIDO_URL": "http://127.0.0.1:8081" }
}
}
}
OAuth tokens are stored at ~/.caido-mcp/token.json. To re-authenticate: run ./caido-mcp-server login --url http://127.0.0.1:8081 from /home/aceos/caido-mcp-server/.