/caido-mode
Full Caido SDK integration for Claude Code. Search HTTP history, replay/edit requests, manage scopes/filters/environments, create findings, export curl commands, and control intercept - all via the official @caido/sdk-client. PAT auth recommended.
$ npx -y skills add caido/skills --skill caido-mode --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/caido-mode
Context preview
The summary Claude sees to decide when to auto-load this skill.
Full Caido SDK integration for Claude Code. Search HTTP history, replay/edit requests, manage scopes/filters/environments, create findings, export curl commands, and control intercept - all via the official @caido/sdk-client. PAT auth recommended.
SKILL.md
caido-mode.SKILL.mdname: caido-mode
description: Full Caido SDK integration for Claude Code. Search HTTP history with HTTPQL, test with curl proxied through Caido (caching auth in reusable static curl config files), add match & replace rules, and organize handoffs into named replay sessions and collections - all via the official @caido/sdk-client. PAT auth recommended.
tags: [worker]
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**:
1. **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. 2. **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 …`, or `send-raw … --name …` for a crafted one).
- **Cache auth in files, don't re-paste it.** Use `export-curl --config` once 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 `-K` config is for your internal testing only; never hand them a `curl -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.jsonIterate 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 opaque `403`/`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-Type` is 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 exact `Content-Type` the endpoint expects (e.g. Google `batchexecute` needs `application/x-www-form-urlencoded;charset=UTF-8`) — a wrong/missing one is a common cause of `400`/`403`. curl sets `Content-Length` itself;
Read more
name: caido-mode description: Full Caido SDK integration for Claude Code. Search HTTP history with HTTPQL, test with curl proxied through Caido (caching auth in reusable static curl config files), add match & replace rules, and organize handoffs into named replay sessions and collections - all via the official @caido/sdk-client. PAT auth recommended. tags: [worker]
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**:
1. **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. 2. **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 …`, or `send-raw … --name …` for a crafted one).
- **Cache auth in files, don't re-paste it.** Use `export-curl --config` once 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 `-K` config is for your internal testing only; never hand them a `curl -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.jsonIterate 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 opaque `403`/`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-Type` is 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 exact `Content-Type` the endpoint expects (e.g. Google `batchexecute` needs `application/x-www-form-urlencoded;charset=UTF-8`) — a wrong/missing one is a common cause of `400`/`403`. curl sets `Content-Length` itself;
Repo: caido/skills

