RedRouter

Blog

Recon and Attack-Surface Mapping with Claude Code on RedRouter

A network cable closet full of patch cables, overlaid with red pixel blocks and the title Recon and attack-surface mapping
Cover based on a photo by Brian Hankins, Public domain

Recon is where a pentest is won or lost, and most of it is bookkeeping: which hosts are in scope, what's running on them, what each one exposes, and what you've already checked. A coding agent is good at that bookkeeping. The problem is that a mainstream assistant often balks the moment the words "attack surface" show up, even with a signed scope in hand.

This is the first post in a series on running a coding agent against a low-refusal model for authorized security work. Here we point Claude Code (or OpenCode) at RedRouter and use it to plan, run, and organize recon on a target you're allowed to test.

Authorized work only. Do this only against systems you own or are authorized in writing to test. The example uses a local, deliberately vulnerable app and a fictional in-scope domain. RedRouter's Terms prohibit using the service to "attack, access, or test systems you do not own or are not authorized to test." No scope, no recon.

What you need

Start Juice Shop on loopback only, so nothing else on your network can reach it:

docker run --rm -p 127.0.0.1:3000:3000 bkimminich/juice-shop

Point the agent at RedRouter

Claude Code

Claude Code reaches a non-Anthropic provider through ANTHROPIC_BASE_URL and a Bearer token in ANTHROPIC_AUTH_TOKEN. Leave ANTHROPIC_API_KEY empty so it doesn't send a competing header. (Sources: Claude Code gateway setup and our tested Claude Code / OpenCode / Cline guide.)

export ANTHROPIC_BASE_URL="https://redrouter.org"
export ANTHROPIC_AUTH_TOKEN="$REDROUTER_API_KEY"
export ANTHROPIC_API_KEY=""
export ANTHROPIC_MODEL="glm-5.3-flash-rr"
export ANTHROPIC_DEFAULT_SONNET_MODEL="glm-5.3-flash-rr"
export ANTHROPIC_DEFAULT_OPUS_MODEL="glm-5.3-flash-rr"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="glm-5.3-flash-rr"
export CLAUDE_CODE_SUBAGENT_MODEL="glm-5.3-flash-rr"
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="1"
claude

The base URL has no /v1; Claude Code appends /v1/messages itself. The token-counting endpoint returns 404, which is fine, because Claude Code estimates locally. Claude Code will warn that it doesn't recognize the model and assume a 200k-token context window; the real window is about 1M, so set it with Claude Code's model-config override if you rely on long context.

We use glm-5.3-flash-rr as the default for agent recon: $0.20 input and $0.80 output per million tokens, with no application and no business verification. An agent resends the whole conversation on every step, so input price is what the bill turns on. deepseek-v4.1-flash-rr works the same way if you want that checkpoint; swap the ID and check the current prices on the models page.

OpenCode

OpenCode uses the OpenAI-compatible endpoint. Save this as opencode.json (OpenCode providers):

{
  "$schema": "https://opencode.ai/config.json",
  "model": "redrouter/glm-5.3-flash-rr",
  "provider": {
    "redrouter": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "RedRouter",
      "options": {
        "baseURL": "https://redrouter.org/v1",
        "apiKey": "{env:REDROUTER_API_KEY}"
      },
      "models": {
        "glm-5.3-flash-rr": { "name": "GLM 5.3 Flash RR" }
      }
    }
  }
}

Stick with glm-5.3-flash-rr in OpenCode for now. In our October 27 test, OpenCode sent reasoning_content back on the second turn with DeepSeek V4.1 Flash RR, and RedRouter rejected it with a 400.

Write the scope down first

Before the agent runs a single command, give it a scope file. It's the most important file in the session, and it lives in the working directory so the agent reads it every time.

SCOPE.md:

# Engagement scope (authorized)
Client: example (fictional)  |  Window: Mon–Thu 09:00–17:00 local
In scope:
- app.staging.example.com
- api.staging.example.com
- http://127.0.0.1:3000  (local Juice Shop lab)
Out of scope:
- *.example.com production, any third-party SaaS, CDNs, SSO provider
Rules:
- No DoS, no brute force against auth, max 10 req/s
- Passive first, active only after I approve each step

Keep the agent's approval prompts on, and don't run it with permission checks skipped. You approve each command, especially anything that touches the network.

The prompts

Feed these one at a time. Each one ends with a file on disk, so the next step builds on the last.

1. Plan, don't run.

Read SCOPE.md. We are doing authorized recon on the in-scope assets only. Write RECON-PLAN.md: passive steps first, then active, each with the tool, the exact command, why we run it, and what signal we're looking for. Flag anything that could reach an out-of-scope host. Do not run anything yet.

2. Passive discovery.

Using the plan, run passive subdomain discovery for staging.example.com (subfinder, and certificate transparency via crt.sh). Write every result to hosts-raw.txt, then filter to only hosts that match SCOPE.md and write hosts-inscope.txt. List anything you dropped and why.

3. Live hosts and tech stack.

Run httpx against hosts-inscope.txt and 127.0.0.1:3000 to get status, title, tech, and TLS info. Save JSON to httpx.json. Summarize the stack per host in SURFACE.md.

4. Content and endpoint discovery on the lab.

Against http://127.0.0.1:3000 only, crawl with katana and run a small ffuf wordlist, max 10 req/s. Add discovered routes, API endpoints, and auth surfaces to SURFACE.md, grouped by host. Mark which ones need authentication.

5. Prioritize.

From SURFACE.md, rank the top 10 things to test next and why: auth flows, admin paths, file uploads, API endpoints taking IDs. For each, give the vulnerability class to check and the test you'd run. Don't exploit anything.

What good output looks like

A useful run produces four files and no surprises:

Signs of a bad run: the agent widens the scope on its own, runs active scans before you approved the plan, or invents endpoints it never saw. Stop it, point it back at SCOPE.md, and re-run the step. Models can still refuse or get things wrong; reduced refusals are not a guarantee, so check every result against the tool output.

What it costs

Recon sessions are input-heavy, because an agent resends the conversation and tool output on every step. Here's the math on catalog prices as of October 29, 2026 (check the models page for current numbers). These are calculations on an assumed workload, not measurements.

Assumed session: 30 agent requests, about 40,000 input tokens and 2,000 output tokens each (1.2M input and 60k output in total).

ModelInput $/MCached input $/MOutput $/MEstimated session cost
glm-5.3-flash-rr$0.20$0.08$0.80$0.29
deepseek-v4.1-flash-rr$1.15$0.115$2.30$1.52

The estimate bills every input token at the full rate. Where cache reads are reported, repeated context bills at the cached rate, so check the Usage page after your run for the real number.

What we still don't know

Next in the series: web-app testing against a local deliberately vulnerable app, using the surface map from this one.

Sources


RedRouter is operated by Marker AI, Inc. It's for systems you own or are authorized in writing to test. New API keys have content storage off; when storage is on, prompts and completions are kept encrypted for up to 30 days. Zero data retention is one switch in Settings, free on monthly plans. See the Terms and Privacy policy.