Imported from caido/skills (
skills/caido-mode/SKILL.md) via skills.sh. Install upstream withnpx skills add caido/skills --skill caido-mode. Copyright stays with the author.
Caido Mode Skill
A CLI over Caido's API (built on the official @caido/sdk-client) for HTTP-history-driven
testing. The tool lives at ~/.claude/skills/caido-mode/caido-client.ts; every command is
npx tsx caido-client.ts <command> and outputs JSON unless noted.
How to operate (read this first)
There are two distinct modes:
- Testing → use
curl, always proxied through Caido. Find a real authenticated request in history, cache its auth into a reusable curl config (a faithful static snapshot of its headers- cookies), then probe with
curl -K auth.cfg "$BASE/path". All traffic must go through Caido (the config carries the proxy), so every request lands in HTTP history.
- cookies), then probe with
- Handoff → use replay sessions + collections. Only when handing a request (or a set) to the user do you materialize it as a named replay session inside a named collection.
Hard rules:
- Everything goes through Caido — except high-volume bruteforce/fuzzing. Never curl a single
target request directly; always via the Caido proxy (the generated config does this; otherwise add
-x <proxy>). The one exception: don't proxy bruteforce/fuzzing tools (ffuf, etc.) or any batch of 100+ requests at once through Caido — it bloats HTTP history. Run those direct (no-x), then bring any interesting hit back into Caido (re-send it through the proxy / promote to Replay) to investigate and hand off. - Test with
curl. Don't spin up replay sessions for probing — that's handoff only. - To show the operator a request, send it to Replay. Whenever you want the operator to see a
specific request, create a named replay session for it (in a named collection if there's more
than one) — that's how they inspect and re-run it in Caido. A request you tested via curl only
becomes something the operator can work with once you promote it into Replay
(
create-session <id> --name …, orsend-raw … --name …for a crafted one). - Cache auth in files, don't re-paste it. Use
export-curl --configonce per target; then reference the config. Don't dump cookies/JWTs into every command (or repeatedly into context). - If you hand the operator a runnable command, make it a FULL self-contained curl (all headers
inline, via
export-curl) — for a PoC or something they'll run outside Caido. The-Kconfig is for your internal testing only; never hand them acurl -K /tmp/…line. - Replay session names are mandatory, and editing a session forces explicit name intent.
- Use collections for multi-request handoffs; refer to sessions/collections by name, not ID.
The primary workflow (do this by default)
# 1. Find a base request that already has the auth/cookies you need.
npx tsx caido-client.ts search 'req.host.cont:"target.com" AND req.path.cont:"/api/user"' --compact
# → 8431 200 GET target.com/api/user/me
# 2. ONCE per target: cache its auth into a reusable curl config.
npx tsx caido-client.ts export-curl 8431 --config
# → writes /tmp/caido/target.com/auth.cfg — a FAITHFUL STATIC snapshot:
# proxy + insecure + compressed + ALL the request's auth/identity headers
# (cookies, Authorization, Origin/Referer, X-*, Sec-*, app-specific headers)
# and prints BASE + the captured header list
# 3. Test with curl. -K carries the proxy + auth, so it goes through Caido into history.
BASE=https://target.com
curl -K /tmp/caido/target.com/auth.cfg "$BASE/api/user/999" # IDOR
curl -K /tmp/caido/target.com/auth.cfg -X POST "$BASE/api/profile" \
-H 'Content-Type: application/json' --data-binary @/tmp/caido/target.com/body.json
Iterate step 3 freely — it's cheap, it's all in Caido, and the big auth blob stays in the file.
Confirm a probe landed in Caido with search 'req.host.cont:"target.com"' --compact.
Send the path exactly as written
When testing path traversal / path-normalization (../, /.., /./, encoded variants), pass
curl --path-as-is — otherwise curl collapses ../ and /./ client-side before sending, so
the server never sees the payload and the test silently passes. Keep the path verbatim:
curl --path-as-is -K /tmp/caido/target.com/auth.cfg "$BASE/api/../../../etc/passwd"
(Likewise add -g/--globoff if the URL contains [ ] { } you don't want curl to interpret.)
The config is a faithful STATIC snapshot (important)
export-curl --config captures every auth/identity header from the base request (not a
curated subset) and inlines the cookies statically. Two deliberate choices, both learned the
hard way:
- All headers, not an allowlist. Modern apps gate authorization on app-specific headers you
can't predict —
x-goog-ext-*,X-Browser-Validation,X-Client-Data,Origin,Referer,X-Same-Domain,Sec-*, … A narrow allowlist silently drops these and you get opaque403/PERMISSION_DENIED. The config now mirrors what actually authorized the request. Only truly per-request/volatile headers are dropped:Host,Content-Length,Content-Type,Connection,Accept-Encoding(curl manages these per request).- ⚠ Because
Content-Typeis dropped, you MUST pass it yourself on every POST/PUT/PATCH:curl -K auth.cfg -X POST "$BASE/path" -H 'Content-Type: application/json' --data-binary @body. Use the exactContent-Typethe endpoint expects (e.g. Googlebatchexecuteneedsapplication/x-www-form-urlencoded;charset=UTF-8) — a wrong/missing one is a common cause of400/403. curl setsContent-Lengthitself; don't add it.
- ⚠ Because
- Static cookies, no jar. It does not use
cookie-jarby default, so curl never writes a response's rotatedSet-Cookieback over your captured-good cookies (servers like Google rotate on every response, including error responses — a write-back jar drifts the session into failure). Need to follow rotation?export-curl <id> --config --cookie-jaropts in.
To drop a specific header: --exclude <name> (repeatable). To omit cookies entirely (e.g. when a
Match & Replace rule injects auth): --exclude cookie.
Other conventions
- Per-target scratch dir:
/tmp/caido/<host>/holdsauth.cfg, body files, notes. $BASE: setBASE=https://<host>once; write requests as"$BASE/path".- Bodies in files: save large/complex bodies once and send with
--data-binary @body.json(the correct use of--data-binary— a byte-exact body). Add-H 'Content-Type: …'per request since the config omits it. - Lazy refresh: the snapshot is static, so when a request starts returning 401/403 (token
expired / cookies aged out), re-run
export-curl <fresh-id> --configto re-snapshot, then retry. - CSRF: the matching
X-CSRF*/double-submit header is captured automatically. For tokens that rotate per action, fetch fresh:T=$(curl -sK auth.cfg "$BASE/csrf" | jq -r .token). - Proxy-injected auth (alternative): instead of a config, a Match & Replace rule can inject
Authorization/cookies on all proxied traffic — thencurl -x <proxy> -k "$BASE/path"needs no headers. See Match & Replace.
Giving commands to the user
To surface a request inside Caido for the operator, send it to Replay (see "Replay sessions"
below) — that's the default. This section is for the other case: handing them a runnable command
(a PoC, or something to run outside Caido). Then always produce a full, self-contained curl —
every header inline, no -K:
npx tsx caido-client.ts export-curl 8431 # full curl, all headers inline (portable PoC)
Drop -x/-k for a portable PoC the user can run anywhere; keep them only if the user is meant
to run it through their own Caido. Never hand the user a curl -K /tmp/... line — that file
is yours.
The proxy
All curl testing must go through Caido's proxy. Its address defaults to the Caido URL (proxy and API share an address). Discover/confirm it any time:
npx tsx caido-client.ts auth-status # prints "proxy": "http://localhost:8080"
export-curl --config bakes the proxy into the config (proxy = "…"). For an ad-hoc curl, add
-x <proxy> -k yourself. Override the proxy only if its listener differs from the API URL —
setup --proxy <addr> or export CAIDO_PROXY=<addr>.
Get the proxy from
auth-status(theproxy/activeUrlfields) — don't parsesecrets.jsondirectly. Auth is URL-keyed now: the address lives under.caido.default/.caido.instances, not.caido.url.
Authentication setup
# One-time: create a PAT in Caido (Dashboard → Developer → Personal Access Tokens), then:
npx tsx caido-client.ts setup <your-pat>
npx tsx caido-client.ts setup <pat> http://192.168.1.100:8080 # non-default instance
npx tsx caido-client.ts setup <pat> http://localhost:8080 --proxy http://localhost:8080
# Or env vars
export CAIDO_PAT=caido_xxxxx
export CAIDO_URL=http://localhost:8080
export CAIDO_PROXY=http://localhost:8080 # only if the proxy differs from the URL
npx tsx caido-client.ts auth-status # check (also prints the proxy)
npx tsx caido-client.ts health # verify instance is up
setup validates the PAT via the SDK's device-code flow (auto-approved by the PAT), then caches
the PAT + access token (+ proxy) to ~/.claude/config/secrets.json. Subsequent runs use the
cached token; a valid cached token works even without the PAT.
Multiple Caido instances
Credentials are keyed by instance URL — two instances on one machine never clobber each other.
setup <pat> <url> stores that instance under its URL (and makes it the active default);
setting up a second URL adds a second entry rather than overwriting the first.
npx tsx caido-client.ts setup <pat-a> http://localhost:8080
npx tsx caido-client.ts setup <pat-b> http://localhost:8081 # added, not overwritten
npx tsx caido-client.ts auth-status # lists configuredInstances + activeUrl
The active instance is CAIDO_URL env → stored default → http://localhost:8080. Select per
shell/agent with CAIDO_URL (concurrency-safe — no shared "current instance" to race on), e.g.
CAIDO_URL=http://localhost:8081 npx tsx caido-client.ts recent. CAIDO_PAT/CAIDO_PROXY env
override the active instance's stored values.
Searching HTTP history (HTTPQL)
npx tsx caido-client.ts search 'req.method.eq:"POST" AND resp.code.eq:200' --compact
npx tsx caido-client.ts search 'req.host.cont:"api"' --limit 50
npx tsx caido-client.ts search 'req.host.cont:"api"' --asc --limit 50 # oldest first (rarely wanted)
npx tsx caido-client.ts recent --compact # newest requests, one line each
npx tsx caido-client.ts get 8431 --compact # full details (JSON) when you need them
npx tsx caido-client.ts get-response 8431 --compact
npx tsx caido-client.ts raw 8431 --out /tmp/caido/target.com/body.json # dump bytes (e.g. a body)
searchis NEWEST FIRST by default (descending by request id).--limit Ntherefore returns the newest N matches. Pass--asc(alias--oldest) only when you actually want oldest first.- To get "the most recent matching X", just run
search '<filter>' --limit N— do NOT pull a large--limitand re-sort client-side (e.g.jq 'sort_by(.createdAt) | reverse'). That sorts only the truncated window you fetched, so any request newer than the Nth result is silently invisible — you'll mistake stale traffic for the latest. Let Caido do the ordering. recentis always newest-first but takes no filter; usesearch --limit Nfor newest-matching-a-filter.--compact→ one terse line per request (id status METHOD host/path).- Prefer
search/recent --compactfor browsing;get/export-curlonce you've picked one.
See the HTTPQL Reference below for the full query language.
Replay sessions — for handoff only
Use these when giving a request to the user. Normal testing uses curl (above), not sessions.
Sessions created from a raw request have their header line endings normalized to CRLF
automatically — a handoff session is never built with bare-LF (\n) endings.
# Create a NAMED session from a history request (name is REQUIRED).
npx tsx caido-client.ts create-session 8431 --name "IDOR /api/user/:id"
npx tsx caido-client.ts sessions # list (alias: replay-sessions)
npx tsx caido-client.ts rename-session "IDOR /api/user/:id" "IDOR - confirmed"
npx tsx caido-client.ts move-session "IDOR - confirmed" "Vuln chain - IDOR to ATO"
# Build a handoff session from a raw request file (CRLF auto-normalized):
npx tsx caido-client.ts send-raw --host target.com --raw @/tmp/req.txt --name "crafted repro"
Editing a session forces name intent
If the user asks you to test inside Replay, use edit / edit-session. Because an edit changes
what a session contains, declare what happens to its name — pass exactly one of
--no-name-change (--nonach) or --new-name "<name>":
npx tsx caido-client.ts edit 8431 --path /api/user/999 --name "IDOR victim 999" # new session
npx tsx caido-client.ts edit-session "IDOR victim 999" --body '{"role":"admin"}' --nonach --compact
npx tsx caido-client.ts edit 8431 --path /api/admin --session "IDOR victim 999" --new-name "priv-esc"
edit preserves cookies/auth from the original request; it supports --method, --path,
--set-header, --remove-header, --body (auto Content-Length), --replace <from>:::<to>, and
connection overrides (--sni, --connect-host, …).
Inspecting an existing replay tab
When a replay tab is already open in Caido and you want to work from its current state, look it up by name or id (no need to re-create it):
npx tsx caido-client.ts get-session "IDOR victim 999" --compact # session + its active entry
npx tsx caido-client.ts replay-entries "IDOR victim 999" --limit 20 # request/response history in the tab
npx tsx caido-client.ts replay-entries "IDOR victim 999" --raw --compact # include raw bytes
session-entries is an alias for replay-entries. Use these to read what's in a tab; use
edit-session (above) to send a modified request into it.
Collections — use them heavily
Collections organize sessions for handoff. Before creating a session, list existing collections and decide where it belongs. Names are mandatory and collections are never auto-created.
npx tsx caido-client.ts collections # query first
npx tsx caido-client.ts create-collection "Swagger - petstore.yaml"
npx tsx caido-client.ts rename-collection "old name" "new name"
| Situation | Collection decision |
|---|---|
| One request reproduced for the user | Default collection — don't create one. Name the session and tell the user the name. |
| A replay tab per endpoint in a JS file | New collection JS File Endpoints. |
| A replay tab per endpoint in a Swagger spec | New collection Swagger - <filename>. |
| A multi-request chain for a vuln | New collection Vuln chain - <description>, steps named 1. …, 2. …. |
All endpoints under /api/v2 |
New collection /api/v2/*. |
Pass collections by name; the CLI resolves it (and tells you to create it first if missing):
npx tsx caido-client.ts create-session 8431 --name "1. login" --collection "Vuln chain - IDOR to ATO"
When you report back, name the collection and sessions — never IDs.
Match & Replace — auto-rewrite traffic
Match & Replace (Caido calls these "Tamper" rules internally) rewrites requests/responses
automatically as they pass through Caido. The killer use: inject auth at the proxy so your
curl commands don't carry it — add a rule that sets Authorization on every proxied request, then
curl -x <proxy> -k "$BASE/path" is authenticated with no -K/headers at all.
A rule is one section (which part) × one operation × a matcher × a replacer, with optional condition (HTTPQL scope) and sources:
| Piece | Choices |
|---|---|
| section | req: req-method req-path req-query req-body req-first-line req-header req-all req-sni · resp: resp-body resp-status resp-first-line resp-header resp-all · ws: ws-up ws-down |
| operation | raw (match within the section) · update/add/remove (header & query only, by name) · method/status only update |
| matcher | --match-value <str> · --match-regex <re> · --match-full (whole section) · --match-name <n> (header/query update/add/remove) |
| replacer | --replace <term> (literal; "" allowed) · --workflow <id> (run a workflow) |
| condition | --condition '<httpql>' — only apply when the request matches (e.g. one host) |
| sources | --sources INTERCEPT,REPLAY,… — which traffic it applies to |
Four gotchas, all defaulted for you:
- New rules are created DISABLED. Enable with
toggle-mr-rule <id> --on. - Default collection is Caido's "Default Collection" (override with
--collection <name|id>). - Default sources is
INTERCEPT(proxy traffic), matching Caido. Add--sourcesto broaden. - JS targets — pick matcher based on what you're matching against.
--match-valueis fine for stable literals (string constants, JSON keys, fixed API paths). Use--match-regexwhen matching near minified identifiers: symbol names rotate on every bundle deploy (e.g._.ex→_.Ww), so a literal rule silently stops matching with no error. Anchor the regex to structurally stable neighbours — surrounding string literals, known function names, fixed JSON keys — rather than the minified identifier itself.
Preview before committing: test-mr-rule applies a rule to a raw request without creating
anything — use it to confirm a rule does what you expect.
# Preview: would this add the header correctly?
npx tsx caido-client.ts test-mr-rule --section req-header --operation add \
--match-name X-Test --replace hi --raw 'GET / HTTP/1.1\r\nHost: t.com\r\n\r\n'
# Inject auth on all proxied requests to one host (then enable it)
ID=$(npx tsx caido-client.ts create-mr-rule --section req-header --operation add \
--match-name Authorization --replace "Bearer eyJ…" \
--condition 'req.host.eq:"target.com"' --name "auth inject" | jq -r '.created.id')
npx tsx caido-client.ts toggle-mr-rule "$ID" --on
# Other patterns
npx tsx caido-client.ts create-mr-rule --section req-header --operation remove \
--match-name If-None-Match --sources REPLAY --name "drop INM" # strip a header
npx tsx caido-client.ts create-mr-rule --section req-body --match-regex '"admin":false' \
--replace '"admin":true' --name "force admin" # body regex
npx tsx caido-client.ts create-mr-rule --section resp-status --replace 403 --name "fake 403" # response
npx tsx caido-client.ts mr-rules # list rules (+ enabled state)
npx tsx caido-client.ts toggle-mr-rule <id> --off
npx tsx caido-client.ts delete-mr-rule <id>
Manage collections with mr-collections, create-mr-collection, rename-mr-collection,
delete-mr-collection; move-mr-rule <id> <collection>; update-mr-rule <id> … re-specs a rule
(same flags as create); rename-mr-rule <id> <name>.
Output control (works with get, get-response, replay, edit, send-raw, edit-session)
| 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 |
Omit the request raw from output |
--headers-only |
Headers only, 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; integers are NOT.
CRITICAL: HTTPQL has NO NOT operator. Use the negated operator variant instead:
ncont(not contains),nlike,nregex,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
Examples
req.method.eq:"POST" AND resp.code.eq:200 # POSTs with 200s
req.host.cont:"api" OR req.path.cont:"/api/" # API traffic
"password" OR "secret" OR "api_key" # bare string searches req AND resp raw
resp.code.gte:400 AND resp.code.lt:500 # 4xx
resp.len.gt:100000 # large responses (data exposure)
req.path.regex:"/(login|auth|signin|oauth)/" # auth endpoints
source:"replay" OR source:"intercept" # tool-generated vs proxied traffic
req.created_at.gt:"2024-01-01T00:00:00Z" # date filter
req.path.ncont:"/static" # exclude (no NOT keyword)
preset:"My Filter" # saved filter preset
Other capabilities (reference)
Findings — surface in Caido's Findings tab
npx tsx caido-client.ts findings --limit 50
npx tsx caido-client.ts create-finding 8431 --title "IDOR on /api/user/:id" \
--description "Reads other users' profiles by changing id" --reporter "rez0" --dedupe-key "idor-user"
npx tsx caido-client.ts update-finding <id> --title "…" --description "…"
Scopes / Filter presets / Environments
npx tsx caido-client.ts create-scope "Target" --allow "*.target.com" --deny "*.cdn.target.com"
npx tsx caido-client.ts create-filter "API 4xx" --query 'req.path.cont:"/api/" AND resp.code.gte:400' --alias "api4xx"
npx tsx caido-client.ts search 'preset:"API 4xx"' --compact
npx tsx caido-client.ts create-env "IDOR-Test"; npx tsx caido-client.ts env-set <env-id> victim_id "user_999"
Fuzzing / intercept / projects / tasks / info
npx tsx caido-client.ts create-automate-session 8431 # configure payloads in UI, then: fuzz <session-id>
npx tsx caido-client.ts intercept-status | intercept-enable | intercept-disable
npx tsx caido-client.ts projects ; npx tsx caido-client.ts viewer ; npx tsx caido-client.ts plugins
Full command reference
Every command (run npx tsx caido-client.ts <command>). Sessions/collections accept a name or
id; output is JSON unless noted. Run --help for full flag lists.
| Command | What it does |
|---|---|
| History & testing | |
search <httpql> |
Search history, newest first. --limit --after --ids-only --asc/--oldest --compact |
recent |
Newest requests. --limit --compact |
get <id> / get-response <id> |
Full request / just the response (output-control flags) |
raw <id> |
Dump byte-exact raw request. --out <file> --response |
export-curl <id> |
Full self-contained curl (for the user) |
export-curl <id> --config |
Reusable -K config — faithful static snapshot of all auth headers + inline cookies (internal). --out <file> · --cookie-jar (follow rotation) · --exclude <h> |
| Send / edit | |
replay <id> --name <n> |
Replay into a new named session. --raw --collection + connection overrides |
send-raw --host <h> --raw <s|@file|-> --name <n> |
Send a raw request via a new named session. --port --tls/--no-tls --collection |
edit <id> |
Edit + send into replay. --method --path --set-header --remove-header --body --replace --session --name/--new-name/--nonach --collection |
edit-session <name|id> |
Edit + send from a session's active entry (requires --nonach or --new-name) |
| Replay tab lookup | |
get-session <name|id> |
Session + active entry. --compact |
replay-entries <name|id> |
Request history in a tab (alias session-entries). --limit --raw |
| Sessions | |
create-session <id> --name <n> |
New named session from a request. --collection |
rename-session <name|id> <new> · move-session <s> <collection> |
Rename / move |
sessions (alias replay-sessions) · delete-sessions <id,id,…> |
List / delete |
| Collections | |
collections (alias replay-collections) |
List collections |
create-collection <name> · rename-collection <c> <new> · delete-collection <name|id> |
Create / rename / delete |
| Fuzzing | create-automate-session <id> · fuzz <session-id> (configure payloads in UI) |
| Findings | findings · get-finding <id> · create-finding <id> --title … · update-finding <id> |
| Scopes | scopes · create-scope <name> --allow --deny · update-scope <id> · delete-scope <id> |
| Filters | filters · create-filter <name> --query [--alias] · update-filter <id> · delete-filter <id> |
| Environments | envs · create-env <name> · env-set <env> <var> <val> · select-env [id] · delete-env <id> |
| Projects | projects · select-project <id> |
| Tasks | tasks · cancel-task <id> |
| Hosted files | hosted-files · delete-hosted-file <id> |
| Intercept | intercept-status · intercept-enable · intercept-disable |
| Match & Replace | mr-rules · mr-collections · create-mr-rule --section … [--operation] [--match-*] [--replace/--workflow] [--name --collection --condition --sources] · test-mr-rule --raw … --section … (preview, no-op) · toggle-mr-rule <id> --on|--off · rename-mr-rule <id> <n> · move-mr-rule <id> <coll> · update-mr-rule <id> … · delete-mr-rule <id> · create-mr-collection <n> · rename-mr-collection <c> <n> · delete-mr-collection <c> |
| Info / auth | viewer · plugins · health · setup <pat> [url] [--proxy] · auth-status |
Architecture
Built on @caido/sdk-client v0.2.0+. No raw fetch — high-level SDK methods plus
client.graphql.query/mutation with gql documents for the few features the SDK doesn't expose.
caido-client.ts # CLI entry — arg parsing + dispatch
lib/
client.ts # SDK Client singleton, SecretsTokenCache, auth, resolveProxy
graphql.ts # gql docs for features not in the SDK
output.ts # raw formatting (truncation, headers-only, raw→curl)
types.ts # OutputOpts
commands/
requests.ts # search, recent, get, get-response, raw, export-curl (+ --config)
replay.ts # replay, send-raw, edit, sessions, collections (CRLF-normalized), automate
findings.ts # findings
management.ts # scopes, filters, environments, projects, hosted-files, tasks
intercept.ts # intercept status/enable/disable
matchreplace.ts # match & replace (tamper) rules — buildTamperSection + commands
info.ts # viewer, plugins, health, setup, auth-status
Instructions for Claude (checklist)
- Test with
curl, always through Caido — the proxy must be in the path (config does this; otherwise-x <proxy>). Exception: bruteforce/fuzzing (ffuf) or 100+ requests at once go direct to avoid bloating HTTP history; bring interesting hits back into Caido. - Cache auth once:
export-curl <id> --config→/tmp/caido/<host>/auth.cfg(faithful static snapshot of ALL auth headers + inline cookies). Test withcurl -K auth.cfg "$BASE/path". - Refresh lazily — only on 401/403/login-redirect, regenerate the config from a fresh request.
- Give the user FULL self-contained curl (
export-curl <id>); never a-Kline. - Browse with
--compact;get/export-curlonly the request you'll work from. - To show the operator a request, send it to Replay (named session). Replay = handoff only, names mandatory; collections used heavily, referred to by NAME.
- Editing a session requires
--nonachor--new-name. - Create findings for anything real.
- NEVER use
NOTin HTTPQL — usene/ncont/nlike/nregex.
Operational notes (shell gotchas)
- Don't batch CLI calls inside
while/forloops. Some shells stripPATHinside loop subshells, sohead/python3/etc. become "command not found" and the loop body fails silently (sessions look like they weren't created). Run eachsend-raw/create-sessionas an individual top-level command, or as a standalonebashscript with an explicitexport PATH=…. search --ids-onlyreturns a JSON array (["123"]), not a bare id — unwrap before reuse, e.g.ID=$(… --ids-only | jq -r '.[0]').sessions/collectionsnow list everything (paginated, not just the first page), so freshly-created items always appear.--limit Ncaps the count if you want a short list.
Error handling
- Auth errors →
auth-status, re-setup <pat>(or setCAIDO_PAT). - curl gets 401/403/login redirect → token expired; refresh the config from a fresh request.
- curl can't connect via proxy → confirm the proxy with
auth-status; Caido must be running. - Connection refused / not ready → Caido isn't up or is still starting; check
health.