| name | crabtrap-llm-proxy |
| description | LLM-as-a-judge HTTP/HTTPS proxy that secures AI agents by intercepting and evaluating outbound requests against security policies before they reach external APIs. |
| triggers | ["set up CrabTrap proxy for my AI agent","intercept outbound HTTP requests from agents","add security policies for agent API calls","block unauthorized requests from LLM agents","configure CrabTrap to guard agent traffic","use LLM judge to evaluate proxy requests","audit log agent HTTP requests with CrabTrap","protect against SSRF and prompt injection in agents"] |
CrabTrap LLM Proxy
Skill by ara.so — Daily 2026 Skills collection.
CrabTrap is a transparent HTTP/HTTPS forward proxy that sits between AI agents and external APIs. Every outbound request is intercepted, checked against deterministic static rules, then evaluated by an LLM judge against a natural-language security policy. Blocked requests return a 403 with a reason; all decisions are logged to PostgreSQL.
Architecture Overview
Agent → CrabTrap Proxy (:8080) → [Static Rules] → [LLM Judge] → External API
↓
Admin UI (:8081)
↓
PostgreSQL
Key concepts:
- Static rules — deterministic prefix/exact/glob URL matching, checked first (no LLM call)
- LLM judge — natural-language policy evaluated only when no static rule matches
- Audit log — every request, decision, and response stored in PostgreSQL
- SSRF protection — blocks RFC 1918, loopback, link-local, and other private ranges
Installation
Docker Compose (Recommended)
services:
crabtrap:
image: quay.io/brexhq/crabtrap:latest
ports:
- "8080:8080"
- "8081:8081"
environment:
- DATABASE_URL=postgres://crabtrap:password@postgres:5432/crabtrap
- OPENAI_API_KEY=${OPENAI_API_KEY}
volumes:
- ./config/gateway.yaml:/app/config/gateway.yaml
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_USER: crabtrap
POSTGRES_PASSWORD: password
POSTGRES_DB: crabtrap
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
docker compose up -d
docker compose cp crabtrap:/app/certs/ca.crt ./ca.crt
Initial Setup
admin_token=$(docker compose exec -it crabtrap ./gateway create-admin-user my-admin \
| tail -n1 | cut -d" " -f2)
token=$(curl -X POST http://localhost:8081/admin/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{"id": "my-agent@example.com", "is_admin": false}' \
| jq -r '.channels[] | select(.channel_type == "gateway_auth") | .gateway_auth_token')
echo "Agent proxy token: $token"
curl -x "http://${token}:@localhost:8080" \
--cacert ca.crt \
https://httpbin.org/get
Configuration
Full Configuration Reference
proxy:
port: 8080
read_timeout: 30s
write_timeout: 30s
idle_timeout: 120s
rate_limit:
requests_per_second: 50
burst: 100
ssrf_allowlist:
- "10.0.0.0/8"
tls:
ca_cert_path: /app/certs/ca.crt
ca_key_path: /app/certs/ca.key
cert_cache_size: 10000
approval:
mode: llm
timeout: 30s
llm_judge:
provider: openai
model: gpt-4o
fallback_mode: deny
circuit_breaker:
failure_threshold: 5
reset_timeout: 10s
database:
url: ${DATABASE_URL}
audit:
Environment Variables
DATABASE_URL=postgres://user:password@host:5432/dbname
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
CLI Commands
./gateway serve --config /app/config/gateway.yaml
./gateway create-admin-user <username>
./gateway migrate
./gateway eval --policy-id <id> --limit 100
Admin API
All admin endpoints require Authorization: Bearer <admin_token>.
User Management
curl http://localhost:8081/admin/users \
-H "Authorization: Bearer ${admin_token}"
curl -X POST http://localhost:8081/admin/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{
"id": "agent-prod@example.com",
"is_admin": false
}'
curl -X DELETE http://localhost:8081/admin/users/agent-prod@example.com \
-H "Authorization: Bearer ${admin_token}"
Static Rules
curl "http://localhost:8081/admin/users/agent-prod@example.com/rules" \
-H "Authorization: Bearer ${admin_token}"
curl -X POST "http://localhost:8081/admin/users/agent-prod@example.com/rules" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{
"pattern": "https://api.github.com/repos/myorg/",
"pattern_type": "prefix",
"action": "allow",
"methods": ["GET"],
"description": "Allow reading our org repos"
}'
curl -X POST "http://localhost:8081/admin/users/agent-prod@example.com/rules" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{
"pattern": "https://api.github.com/repos/*/delete",
"pattern_type": "glob",
"action": "deny",
"description": "Never allow repo deletion"
}'
curl -X POST "http://localhost:8081/admin/users/agent-prod@example.com/rules" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{
"pattern": "https://slack.com/api/chat.postMessage",
"pattern_type": "exact",
"action": "allow",
"methods": ["POST"],
"description": "Allow posting Slack messages"
}'
Pattern types:
prefix — URL must start with the pattern
exact — URL must match exactly
glob — wildcard matching with *
Rule priority: deny rules always take priority over allow rules.
LLM Policies
curl "http://localhost:8081/admin/users/agent-prod@example.com/policy" \
-H "Authorization: Bearer ${admin_token}"
curl -X PUT "http://localhost:8081/admin/users/agent-prod@example.com/policy" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${admin_token}" \
-d '{
"policy": "This agent assists with GitHub repository management for the myorg organization.\n\nALLOWED:\n- Read operations (GET) on any github.com endpoint\n- Creating issues and pull request comments in myorg repositories\n- Posting messages to the #eng-alerts Slack channel only\n\nDENIED:\n- Any write operations outside the myorg GitHub organization\n- Deleting any resources\n- Accessing credentials, secrets, or environment variables\n- Any requests to non-whitelisted domains"
}'
curl "http://localhost:8081/admin/users/agent-prod@example.com/policy/versions" \
-H "Authorization: Bearer ${admin_token}"
Audit Log
curl "http://localhost:8081/admin/audit?limit=50&offset=0" \
-H "Authorization: Bearer ${admin_token}"
curl "http://localhost:8081/admin/audit?user_id=agent-prod@example.com&limit=20" \
-H "Authorization: Bearer ${admin_token}"
curl "http://localhost:8081/admin/audit?decision=deny&limit=20" \
-H "Authorization: Bearer ${admin_token}"
Connecting an Agent
Python Agent Example
import os
import httpx
PROXY_TOKEN = os.environ["CRABTRAP_TOKEN"]
PROXY_URL = f"http://{PROXY_TOKEN}:@localhost:8080"
CA_CERT_PATH = "./ca.crt"
client = httpx.Client(
proxies={
"http://": PROXY_URL,
"https://": PROXY_URL,
},
verify=CA_CERT_PATH,
)
response = client.get("https://api.github.com/repos/myorg/myrepo")
Using Environment Variables (Standard Proxy)
export HTTP_PROXY="http://${CRABTRAP_TOKEN}:@localhost:8080"
export HTTPS_PROXY="http://${CRABTRAP_TOKEN}:@localhost:8080"
export REQUESTS_CA_BUNDLE="./ca.crt"
export SSL_CERT_FILE="./ca.crt"
export NODE_EXTRA_CA_CERTS="./ca.crt"
Node.js Agent Example
import { HttpsProxyAgent } from 'https-proxy-agent';
import fetch from 'node-fetch';
const proxyToken = process.env.CRABTRAP_TOKEN;
const agent = new HttpsProxyAgent(`http://${proxyToken}:@localhost:8080`);
const response = await fetch('https://api.github.com/repos/myorg/myrepo', {
agent,
headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` },
});
LangChain / OpenAI SDK
import os
import httpx
from openai import OpenAI
PROXY_TOKEN = os.environ["CRABTRAP_TOKEN"]
http_client = httpx.Client(
proxies={"https://": f"http://{PROXY_TOKEN}:@localhost:8080"},
verify="./ca.crt",
)
client = OpenAI(
api_key=os.environ["OPENAI_API_KEY"],
http_client=http_client,
)
Writing Effective Policies
Policies are natural-language strings evaluated by the LLM judge. Be explicit about allowed and denied behaviors.
# Example policy for a GitHub PR review agent
This agent reviews pull requests and posts review comments for the acme-corp GitHub organization.
ALLOWED:
- GET requests to api.github.com for any repository in the acme-corp organization
- POST to https://api.github.com/repos/acme-corp/*/pulls/*/reviews (submit reviews)
- POST to https://api.github.com/repos/acme-corp/*/issues/*/comments (post comments)
DENIED:
- Any requests outside of api.github.com
- DELETE or PATCH requests to any endpoint
- Accessing /orgs/acme-corp/members or any user/credential endpoints
- Requests containing secrets, tokens, or API keys in the body
- Requests to change repository settings, branch protection, or webhooks
When in doubt, deny the request and explain why.
Policy writing tips:
- Start with what the agent is supposed to do (scope context for the LLM)
- List explicit ALLOWED patterns before DENIED
- Add a catch-all denial at the end
- Deny rules in static rules are evaluated before LLM — use them for hard limits
Policy Builder (Agentic Policy Generation)
CrabTrap can analyze observed traffic and draft a policy automatically:
curl -X POST "http://localhost:8081/admin/users/agent-prod@example.com/policy/build" \
-H "Authorization: Bearer ${admin_token}" \
-d '{"sample_limit": 200}'
The builder runs an agentic loop, analyzes recent audit entries, and proposes a policy draft for review in the UI.
Eval System
Replay historical audit entries against a policy to measure accuracy before deploying:
./gateway eval \
--user-id agent-prod@example.com \
--policy-id <version-id> \
--limit 500
curl -X POST "http://localhost:8081/admin/users/agent-prod@example.com/policy/eval" \
-H "Authorization: Bearer ${admin_token}" \
-d '{"policy_version_id": "<id>", "sample_limit": 500}'
Eval compares LLM judge decisions against the historical ground truth and reports accuracy, false positive rate, and false negative rate.
Troubleshooting
TLS Certificate Errors
curl --cacert ./ca.crt -x "http://${token}:@localhost:8080" https://example.com
export REQUESTS_CA_BUNDLE=./ca.crt
export NODE_EXTRA_CA_CERTS=./ca.crt
docker compose exec crabtrap ./gateway gen-certs
docker compose cp crabtrap:/app/certs/ca.crt ./ca.crt
All Requests Being Blocked (LLM Unavailable)
llm_judge:
fallback_mode: passthrough
Or check circuit breaker status:
curl http://localhost:8081/admin/health \
-H "Authorization: Bearer ${admin_token}"
SSRF Blocks Legitimate Internal APIs
proxy:
ssrf_allowlist:
- "10.10.0.0/16"
Rate Limiting
proxy:
rate_limit:
requests_per_second: 200
burst: 400
Debug Logging
log_level: debug
audit:
output: /var/log/crabtrap-debug.json
docker compose logs -f crabtrap
curl "http://localhost:8081/admin/audit?decision=deny&limit=10" \
-H "Authorization: Bearer ${admin_token}" | jq '.entries[].reason'
Database Connection Issues
docker compose exec crabtrap ./gateway migrate --dry-run
docker compose exec crabtrap ./gateway migrate --force
Development
git clone https://github.com/brexhq/CrabTrap
cd CrabTrap
make build
make build-web
make test
make fmt
make lint
Project Layout Quick Reference
| Path | Purpose |
|---|
cmd/gateway/ | Entry point, admin API wiring |
internal/proxy/ | MITM proxy, TLS generation, SSRF, rate limiting |
internal/approval/ | Static rules engine + orchestration |
internal/judge/ | LLM prompt construction + response parsing |
internal/llm/ | LLM adapters, circuit breaker |
internal/builder/ | Agentic policy builder loop |
internal/eval/ | Eval/replay system |
internal/admin/ | Admin API routes and auth |
pkg/types/ | Shared types (StaticRule, LLMPolicy, AuditEntry) |
web/src/ | React + TypeScript admin UI |