Caido is a modern, lightweight web security testing proxy written in Rust. It provides core penetration testing capabilities including request interception, replay, and automation features as a lighter alternative to Burp Suite. The clean modern UI and cross-platform support make it ideal for security researchers and penetration testers.
brew install caido
caido --version
# Download from https://caido.io/download
chmod +x Caido-x.x.x.AppImage
./Caido-x.x.x.AppImage
# Download installer from https://caido.io
# Run the .exe installer or portable executable
caido.exe --version
docker run -d -p 8080:8080 caido/caido:latest
caido
# Launches on http://localhost:8080 by default
caido --port 9090
caido --headless --listen 0.0.0.0:8080
caido --tls
# Generate and trust CA certificate for MITM
| Browser | Steps |
|---|
| Chrome | Settings → Advanced → System → Proxy settings → Manual proxy configuration → HTTP: localhost:8080 |
| Firefox | Settings → Network Settings → Manual proxy configuration → HTTP Proxy: localhost:8080 |
| Safari | System Preferences → Network → Advanced → Proxies → Web Proxy (HTTP) → localhost:8080 |
| Edge | Settings → Advanced → System → Open proxy settings → Manual proxy setup |
export http_proxy=http://localhost:8080
export https_proxy=http://localhost:8080
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
networksetup -setwebproxy "Wi-Fi" localhost 8080
networksetup -setsecurewebproxy "Wi-Fi" localhost 8080
# Export CA certificate from Caido UI
# macOS
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain caido-ca.pem
# Linux (Ubuntu/Debian)
sudo cp caido-ca.pem /usr/local/share/ca-certificates/
sudo update-ca-certificates
# Windows
certutil -addstore -f "ROOT" caido-ca.pem
| Action | Steps |
|---|
| Intercept All | Click “Intercept” button → Select “All” |
| Intercept Requests Only | Click “Intercept” → Select “Requests” |
| Intercept Responses Only | Click “Intercept” → Select “Responses” |
| Disable Interception | Click “Intercept” → Select “Off” |
Original Request:
GET /api/user/123 HTTP/1.1
Host: example.com
Authorization: Bearer token123
Modified Request:
GET /api/user/456 HTTP/1.1
Host: example.com
Authorization: Bearer token456
| Action | Shortcut |
|---|
| Forward Request | Click “Forward” or press F |
| Drop Request | Click “Drop” or press D |
| Send to Replay | Drag to Replay tab |
| Toggle Request/Response | Tab key |
# In Caido UI:
1. Right-click intercepted request
2. Select "Send to Repeater"
3. Click "Send" to replay request
4. Compare original vs. modified response
Original:
POST /api/login HTTP/1.1
Content-Type: application/json
{"username":"admin","password":"pass123"}
Modified:
POST /api/login HTTP/1.1
Content-Type: application/json
{"username":"admin","password":"newpass"}
| Feature | Usage |
|---|
| Side-by-side View | Compare two responses visually |
| Diff Highlighting | Automatic diff between requests |
| Save Response | Export response for archival |
| Pretty Print | Auto-format JSON/XML responses |
# Record request sequence:
1. Click "Macros" tab
2. Click "Record New Macro"
3. Perform actions in browser (login, navigate)
4. Stop recording
5. Macro is saved and can be replayed
1. Right-click request → "Send to Intruder"
2. Click payload positions to mark variables
3. Choose attack type (Sniper, Battering Ram, etc)
4. Configure payloads
5. Click "Start Attack"
| Type | Description | Example |
|---|
| Simple List | Predefined wordlist | numbers.txt (0-1000) |
| Custom Iterator | Generate sequences | A, AA, AAA, AAAA |
| Date Generator | Date sequences | 2026-01-01, 2026-01-02 |
| Recursive Grep | Extract from response | Extract from HTML |
| Character Frobber | Mutate characters | abc → abd, abe, etc |
| Attack Type | Usage |
|---|
| Sniper | Single placeholder, one wordlist |
| Battering Ram | Multiple placeholders, same wordlist |
| Pitchfork | Multiple placeholders, synced wordlists |
| Cluster Bomb | Multiple placeholders, all combinations |
# Endpoint: GET /api/user/[ID]?role=[ROLE]
# Sniper attack on ID parameter with 1-100
GET /api/user/1?role=user HTTP/1.1
GET /api/user/2?role=user HTTP/1.1
GET /api/user/3?role=user HTTP/1.1
...
GET /api/user/100?role=user HTTP/1.1
| Filter Operator | Example |
|---|
| Status Code | status == 200 |
| Response Length | length > 1000 |
| Response Time | time > 500 |
| Contains Text | contains “admin” |
| Regular Expression | regex “error[0-9]+“ |
# In Settings → Scope:
1. Click "Add Scope"
2. Enter domain/path pattern
3. Select "Include" or "Exclude"
4. Examples:
- example.com (all subdomains)
- *.api.example.com (API subdomains)
- /admin/* (admin paths only)
| Rule | Pattern | Matches |
|---|
| Exact Domain | example.com | Only example.com |
| Wildcard | *.example.com | Sub.example.com, api.example.com |
| Path Prefix | /api/* | /api/users, /api/posts |
| Regex | ^/admin/.* | /admin/users, /admin/settings |
# In Proxy Settings:
- Enable "Only show requests in scope"
- Enable "Only intercept requests in scope"
| Filter | Syntax | Example |
|---|
| Host | host:example.com | host:api.example.com |
| Method | method:GET | method:POST |
| Path | path:/api | path:/admin |
| Status | status:200 | status:4||5 (4xx or 5xx) |
| Contains | contains:password | contains:“bearer” |
| Regex | regex:^/api | regex:.json$ |
# Multiple filters (AND logic):
host:api.example.com method:POST status:500
# Exclude patterns:
host:cdn.example.com -contains:image
# Find all POST requests
method = "POST"
# Find requests with specific header
headers.contains("Authorization")
# Find responses with status 200
response.status = 200
# Combine conditions
method = "POST" and host = "api.example.com"
# Find all API requests
host = "api.example.com"
# Find login attempts
path.contains("login")
# Find requests with API keys
headers.contains("api-key")
# Find large responses
response.body.length > 10000
# Find JSON responses
response.headers["content-type"].contains("json")
# Find requests with specific parameter
request.query["user_id"]
# Find vulnerable patterns
response.body.contains("error") and response.status = 500
# In Settings → Rules:
1. Click "Add Rule"
2. Define Match pattern (regex)
3. Define Replace value
4. Enable rule
| Pattern | Match | Replace | Use Case |
|---|
| Auth Token | Bearer\s+(\S+) | Bearer newtoken123 | Replace tokens |
| User ID | user_id=\d+ | user_id=999 | ID manipulation |
| CSRF Token | csrf=(\S+) | csrf=validtoken | Bypass CSRF |
| Timestamp | timestamp=\d+ | timestamp=1234567890 | Time manipulation |
# Replace Authorization header
Match: Authorization: Bearer.*
Replace: Authorization: Bearer admin_token
# Inject XSS payload
Match: search=(.*)
Replace: search=<img src=x onerror=alert('xss')>
# Bypass WAF
Match: SELECT.*FROM.*WHERE
Replace: SeLeCt * FrOm users WhErE
1. Click "Workflows" tab
2. Click "New Workflow"
3. Define workflow steps (conditions, actions)
4. Save and enable
# Auto-add custom header to all requests
Condition: host = "api.example.com"
Action: Add header "X-Security-Test: true"
# Log sensitive requests
Condition: headers.contains("Authorization")
Action: Log request to security audit
# Auto-replay failed requests
Condition: response.status = 500
Action: Send to repeater for investigation
# caido_plugin.py example
from caido import Hook, Request, Response
def on_request(req: Request) -> Request:
"""Modify requests before sending"""
req.headers["X-Custom"] = "value"
return req
def on_response(res: Response) -> Response:
"""Modify responses after receiving"""
# Log or analyze response
print(f"Response status: {res.status}")
return res
# Copy plugin to plugins directory
cp my_plugin.py ~/.caido/plugins/
# Reload Caido to activate
# Or click Settings → Plugins → Reload
| Feature | Caido | Burp Suite |
|---|
| License | Community (Free) | Paid (Professional) |
| Language | Rust | Java |
| Memory Usage | Low | High |
| UI | Modern (Qt) | Heavy (Java Swing) |
| Startup Time | Fast | Slow |
| Interception | Yes | Yes |
| Repeater | Yes (Full) | Yes |
| Intruder | Yes | Yes (Pro) |
| Scanner | No | Yes (Pro) |
| Macros | Yes | Yes |
| Plugins | Limited | Extensive (BApp) |
| Cross-platform | Yes | Yes |
# Enable TLS interception:
1. Start Caido with --tls flag
2. Install CA certificate in system
3. Route traffic through proxy
4. HTTPS requests now decrypted and re-encrypted
import requests
# Send request through Caido proxy
proxies = {
'http': 'http://localhost:8080',
'https': 'http://localhost:8080'
}
response = requests.get(
'https://example.com/api',
proxies=proxies,
verify=False # Ignore cert warnings
)
# Zaproxy → Caido proxy chain
# Caido listens on 8080
# Configure other tools to proxy through Caido
# Command-line automation
curl -x http://localhost:8080 https://example.com/api
# Browser extension for cookie/auth injection
# Use interceptor to modify auth headers mid-request
# macOS: Trust CA in Keychain
open caido-ca.pem
# Linux: Update CA store
sudo update-ca-certificates --fresh
# Force curl to trust Caido CA
curl --cacert caido-ca.pem https://example.com
# Verify TLS is enabled:
caido --tls --listen 0.0.0.0:8080
# Check if certificate is installed:
# macOS: Keychain Access → System → Caido CA
# Linux: /etc/ssl/certs/ contains Caido cert
# Restart proxy and browser
# Check proxy performance:
1. Review request queue in Caido
2. Disable unnecessary features (logging, replay)
3. Increase buffer size in settings
4. Run Caido on dedicated machine for high-traffic testing
# Clear request history:
Caido UI → Sessions → Clear History
# Or restart Caido:
caido --headless (restart fresh session)
1. Configure scope to target domain only
2. Enable interception for requests only
3. Perform manual exploration (2-3 minutes)
4. Review all requests in history
5. Test high-value endpoints with Intruder
6. Document findings with screenshots
# Disable response interception if not needed:
Settings → Proxy → Intercept: Requests Only
# Clear history periodically:
Sessions → Clear History
# Use filters to reduce displayed requests:
path:/api (only show API requests)
# Use Intruder for batch testing:
1. Export target URLs to file
2. Create Intruder payload from file
3. Filter responses by status code
4. Export results to CSV