RedSutureDeveloper Docs
⌘K
Developer documentation

Pentest your app in minutes.

One API call starts an autonomous pentest. Poll it for live agent activity and findings, each with a proof of concept and a ready-to-merge fix.

Live dashboard: configure, launch and watch scans visually in the RedSuture dashboard — no code required.

Quickstart

Make sure Docker is running and your environment is set, then start a scan and poll it.

1. Configure

bash
# .env.local
RS_MODEL=gemini/gemini-4-argon
GEMINI_API_KEY=your-gemini-api-key

2. Start a scan

bash
curl -X POST http://localhost:3333/api/scan \
  -H "Content-Type: application/json" \
  -d '{"targets":["https://api.example.com"],"targetType":"url","mode":"quick"}'
# → { "runId": "api-example-com_m1a2b3", "status": "running" }

3. Poll for progress & findings

bash
curl "http://localhost:3333/api/scan/api-example-com_m1a2b3"
Only scan assets you own or have explicit written permission to test. The engine actively attacks the target.

Authentication

The API routes are currently unauthenticated — there is no server session or API key yet. In the browser, the app uses a client-side flag only to personalize and gate the UI; it does not protect the routes.

Before deploying publicly, add a session / API-key layer and protect /api/scan*.

Start a scan

POST/api/scan

Starts a pentest in the background and returns a runId immediately.

Body

targetsstring[]required

One or more targets. Blank entries are dropped.

targetstringoptional

Single-target convenience; used if targets is empty.

targetTypestringoptional

url · repo · dir · whitebox · list. Default url.

modestringoptional

quick · standard · deep. Default quick.

llmstringoptional

Primary model, LiteLLM format. Default gemini/gemini-4-argon. Fallbacks follow automatically.

instructionsstringoptional

Scope notes, credentials or focus passed to the engine.

schedulestringoptional

manual · weekly · monthly · daily · continuous. Default manual.

Example

javascript
const res = await fetch('/api/scan', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    targets: ['https://api.example.com'],
    targetType: 'url',
    mode: 'quick',
  }),
});
const { runId } = await res.json();

Poll a scan

GET/api/scan/:runId

Returns a live snapshot. The dashboard polls this every 2 seconds until status is complete or error.

Query

agentstringoptional

When set to an agent id in the run, includes that agent's steps. Omit to skip the step read.

Response

json
{
  "runId": "api-example-com_m1a2b3",
  "status": "running",            // running | complete | error
  "progress": 62,
  "findings": [ { "id", "title", "severity", "cvss", "endpoint", "poc", "patch" } ],
  "agents": [ { "id", "name", "status", "parentId", "task", "skills", "depth" } ],
  "activeAgents": 3,
  "steps": [ { "seq", "kind": "tool", "tool": "browser_navigate", "text": "..." } ],
  "counts": { "critical": 1, "high": 3 },
  "logs": [ "..." ]
}

Polling loop

javascript
const timer = setInterval(async () => {
  const data = await fetch(`/api/scan/${runId}`).then(r => r.json());
  render(data.agents, data.findings, data.progress);
  if (data.status === 'complete' || data.status === 'error') clearInterval(timer);
}, 2000);

List scans

GET/api/scan

Returns every scan, newest first.

json
{
  "scans": [
    { "runId": "...", "target": "https://api.example.com", "targetType": "url",
      "mode": "quick", "startedAt": "2026-10-09T10:00:00.000Z", "status": "complete" }
  ]
}

Agents & steps

RedSuture runs a graph of specialized agents (recon, exploitation, validation, remediation). The poll response includes the live agents tree; request one agent's steps to see exactly what it's doing.

Agent shape

typescript
interface Agent {
  id: string;
  name: string;              // "Recon", "Exploitation", ...
  status: string;            // running | waiting | completed | failed | ...
  parentId: string | null;   // tree edges
  task: string | null;       // what it's doing right now
  skills: string[];          // ["bola", "sqli", "proxy"]
  depth: number;             // indentation in the tree
}

Fetch an agent's steps

bash
curl "http://localhost:3333/api/scan/<runId>?agent=exploit"
# steps: [ { kind: "message" | "tool" | "output", tool?, role?, text } ]
Steps come from the engine's database and require Node 22.5+ (built-in node:sqlite). On older Node the agent tree still works; steps come back empty.

Open a fix PR

POST/api/github/pr

Builds a pull-request payload for a finding's patch.

Stub. This route constructs and returns the payload but does not call the GitHub API — no branch or PR is created. Wire it to Octokit with a token to make it real.

Body

repoUrlstringrequired

https://github.com/owner/repo or owner/repo.

targetBranchstringoptional

Default main.

vulnIdstringoptional

Used in the generated branch name.

vulnTitlestringoptional

Used in the PR title.

patchDiffstringoptional

The patch to attach.

Models & environment

The engine reaches 100+ model providers. Set the primary model, a key for each provider you use, and an optional fallback chain. Models whose provider has no key are skipped.

bash
# Primary model (LiteLLM format)
RS_MODEL=gemini/gemini-4-argon

# One key per provider (RS_API_KEY is a catch-all)
GEMINI_API_KEY=...
MINIMAX_API_KEY=...
DEEPSEEK_API_KEY=...
OPENROUTER_API_KEY=...
ANTHROPIC_API_KEY=...

# Optional: comma-separated backup models, tried in order on provider failure.
# Unset → gemini-4-argon → minimax-m3.1-flash → deepseek-v4.1-flash → glm-5.3 → claude-opus-5
RS_MODEL_FALLBACKS=

# Optional: path to the engine binary
RS_ENGINE_BIN=

Each scan tries the requested model first, then each fallback — every attempt is a real scan. Pass llm on the request to override the primary per scan.

Scan engine

Each scan runs RedSuture's autonomous engine in an isolated workspace. The engine writes its results to a per-run directory that the poll route reads back.

  • Every run produces SARIF 2.1.0 findings, a live agent graph, a per-agent step stream, and logs.
  • A run with no findings and a run with findings are both successful completions.
  • If the engine is unavailable or every model fails, the run is marked error — never a fabricated result.
  • Run output stays on your machine and is git-ignored.