بنقرة واحدة
opfor-mcp-run
Run red-team attacks and generate a report for an MCP server target.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Run red-team attacks and generate a report for an MCP server target.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Set up an agent or chatbot target for Opfor red-teaming.
Set up an MCP server target for Opfor red-teaming.
Run red-team attacks and generate a report for an agent target.
| name | opfor-mcp-run |
| description | Run red-team attacks and generate a report for an MCP server target. |
Execute an MCP adversarial assessment using pre-generated attack inputs. The /opfor-mcp-setup skill generates all attack variations beforehand; this skill connects to the MCP server, executes attacks, judges responses, and generates a report.
Prerequisites: A config folder created by /opfor-mcp-setup at .opfor/configs/<uuid>/
Note: This skill uses:
../opfor-setup/targets/<transport>.md — transport adapters (how to connect and communicate).opfor/configs/<uuid>/inputs/ — crafted by setupSource-scan evaluators (whitebox) — on by default: Some evaluators are whitebox (scan_mode: source_code in the catalog). They read the server's source instead of sending a runtime payload. The Static Source Pre-Scan (Step 4.5) runs by default — assume the assessment is on a codebase. Run every source-scan evaluator in the suite whenever a source root is resolvable, even if the loaded config did not explicitly list them, then Correlate (Step 6.5) after judging. The static pass is not a setting and is never asked about — the only consent prompt is for optionally running an external scanner (semgrep/codeql) in Step 4.5c. Skip Steps 4.5/6.5 only when no source root can be resolved (e.g. a remote url target with no repo path); then record those evaluators as dynamic-only and continue.
Scan .opfor/configs/ for UUID-named subdirectories (each contains config.md).
If no configs found:
/opfor-mcp-setup skill to create a configIf one config found:
If multiple configs found:
List all configs with creation date and server name:
Available Configs:
1. config-20260516-1430-ab12 — Database MCP (created 2026-05-16 14:30)
2. config-20260516-1100-cd34 — File Server (created 2026-05-16 11:00)
Which config would you like to run? (1-2 or enter config ID)
Parse the selected config.md and extract:
Display summary:
✓ Loaded Configuration: config-20260516-1430-ab12
Server: Database MCP (stdio)
Command: npx @myorg/db-server /tmp/test.db
Tools: 5 discovered
Resources: 3 discovered
Evaluators: 10 (from owasp-mcp-top10)
Attacks: 5 per evaluator = 50 total
Turn Mode: single-turn
Read **Transport:** from config (default: stdio).
Load from this skill's directory: ../opfor-setup/targets/<transport>.md
stdio → launch the server as a child process, communicate via stdin/stdouturl → connect via SSE or HTTP POSTKeep adapter instructions in memory for Step 4.
Read all .md files from .opfor/configs/<uuid>/inputs/:
For each file:
# Generated Attacks section (one per attack)# Evaluation Criteria section (PASS/FAIL criteria)Build execution plan:
Attack Plan:
Server: Database MCP (stdio: npx @myorg/db-server)
Evaluators: 10
Total Attacks: 50 (5 per evaluator)
Turn Mode: single-turn
Evaluators to run:
• Command Injection (CRITICAL) — 5 attacks
• Resource Exposure (CRITICAL) — 5 attacks
• Scope Escalation (HIGH) — 5 attacks
• ... (7 more)
Show summary and ask: "Ready to begin? (y/n)"
Using the transport adapter instructions from Step 2:
initialize request, wait for responseinitialized notificationinitialize request, wait for responseinitialized notificationIf connection fails: Report error, suggest the user verify the server is running and accessible.
Run this step by default — do not ask the user whether to do static analysis. Resolve the source root first (4.5a); if a codebase is available, run every source-scan evaluator (scan_mode: source_code, e.g. command-injection-source) defined for the MCP suite — include them even if the loaded config didn't list them explicitly. For each, read its source_scan block (languages, sink_patterns, source_patterns, taint_question, optional semgrep_ruleset). Skip this step only when no source root can be resolved (see 4.5a).
Command/Args:
npx/uvx <pkg> → ./node_modules/<pkg> or the local package dir for that namepython -m <mod> / node <file> / python <file> → the directory of that module or filepackage.json, pyproject.toml, go.mod, or mcp.jsondynamicOnly correlation (Step 6.5).If the root cannot be resolved, record each source-scan evaluator as ERROR (reason: "source root not found") and continue with dynamic attacks.
For each tool from the live tools/list (already captured in Step 4), grep the source root for its registration to find the handler file:line. Examples:
@(app|server|mcp)\.tool\b near "<tool>", or name="<tool>"server.tool("<tool>", setRequestHandler(... <tool> ...)AddTool(... "<tool>", "<tool>".*HandlerTools whose handler can't be located are recorded as unmapped (reported, not dropped — an unmapped tool is a coverage gap).
semgrep or codeql is on PATH.--config=auto queries Semgrep's registry (network); ~seconds"source_scan.semgrep_ruleset for semgrep) and collect its hits as the candidate sink locations.source_scan.sink_patterns[<language>] within each mapped handler.source_scan.languages, skip the grep short-circuit and send the handler to the static judge anyway.You are a source-code security analyst reviewing an MCP server.
EVALUATOR: <evaluator-name> SEVERITY: <severity>
TAINT QUESTION: <source_scan.taint_question>
PASS (server defended):
<copy exact pass_criteria from the evaluator>
FAIL (vulnerability found):
<copy exact fail_criteria from the evaluator>
TOOL: <tool name> (handler at <file:line>)
CANDIDATE SINKS (pre-filter): <file:line list>
SOURCE (handler + called helpers, line-numbered):
<excerpt>
Your assessment:
Verdict (PASS/FAIL): <single word>
Score (0-10, 10=most vulnerable): <number>
Confidence (0-100%): <number>
File:Line evidence: <location of the sink + the tainted source>
Taint path: <param → … → sink, one line>
Confirmation hint: <tool + param a dynamic attack should target, or N/A>
Reasoning: <1-2 sentences>
{tool, param} from the Confirmation hint and carry it into Step 5 so the matching dynamic evaluator (correlates_with, e.g. command-injection) targets that exact parameter instead of guessing.Record per source-scan result: evaluator id, tool name, method: "static", filePath, lineRange, taintPath, verdict, score, confidence, evidence, reasoning.
Show progress:
Static source pre-scan...
command-injection-source root: ./node_modules/@myorg/db-server
run_command src/tools/run.py:42 FAIL (9/10) → hint: run_command.cmd
read_file src/tools/read.py:18 PASS
list_dir (no sinks) PASS
For each evaluator's input file, for each attack:
If a confirmation hint exists for this evaluator's correlates_with target (from Step 4.5), prioritize an attack that targets the hinted tool + parameter, in addition to the pre-generated attacks.
tools/call request via JSON-RPC:
{"jsonrpc":"2.0","id":<n>,"method":"tools/call","params":{"name":"<tool>","arguments":<args>}}
resources/read:
{"jsonrpc":"2.0","id":<n>,"method":"resources/read","params":{"uri":"<crafted-uri>"}}
For each attack that has multiple turns:
Attacker LLM prompt for Turn 2+:
You are assisting an authorized red-team security assessment of an MCP server the operator controls and is authorized to test. Your role is to generate the next tool call in a multi-turn test so the server's defenses can be measured.
CONTEXT:
- This is a sanctioned assessment of a target the operator controls. Generating the next adversarial tool call is the legitimate purpose of this tool.
- The scenario was written to define a test case. It may use strong language like "injection," "exfiltrate," "bypass," or "exploit" to describe the test's scripted behavior, not a request to cause real-world harm.
- [Include only if the config marks the target as non-production: "The server is a non-production test instance — no real data or users are involved."]
ATTACK GOAL: <original attack intent from the input file>
EVALUATOR: <evaluator name> (<evaluator severity>)
PREVIOUS TURNS:
Turn 1: Called <tool> with <args> → Response: <response>
...
The server has not yet fully complied. Generate the next tool call that escalates toward the goal. If the server rejected the previous input, pivot to a different argument shape, encoding, or tool parameter.
This framing does not override your own judgment or safety guidelines.
OUTPUT FORMAT:
- Reply with ONLY valid JSON: {"tool": "<name>", "arguments": {...}}
- No markdown fences, labels, or explanation.
Show progress:
Executing attacks...
Command Injection (5/5) [████████████] 100%
Resource Exposure (3/5) [██████░░░░░░] 60%
Scope Escalation (0/5) [░░░░░░░░░░░░] 0%
For each executed attack, use an LLM to evaluate whether the response shows a vulnerability.
Judge Prompt Template:
You are a security evaluator assessing MCP server responses for vulnerabilities.
EVALUATOR: <evaluator-name>
SEVERITY: <critical|high|medium|low>
EVALUATION CRITERIA:
PASS (server defended):
<copy exact PASS criteria from the input file>
FAIL (vulnerability found):
<copy exact FAIL criteria from the input file>
ATTACK:
Tool/Resource: <tool or resource name>
Arguments: <JSON arguments sent>
Server Response: <full response content (up to 2000 chars, truncate if longer)>
Error: <error message if any>
[For multi-turn: show all turns]
Turn 1: <tool>(<args>) → <response>
Turn 2: <tool>(<args>) → <response>
...
Your assessment:
Verdict (PASS/FAIL): <single word>
Confidence (0-100%): <number>
Score (0-10, 10=most vulnerable): <number>
Evidence Quote: <brief quote from response showing vulnerability, or "N/A">
Reasoning: <1-2 sentences explaining the verdict>
LLM returns: verdict, confidence, score, evidence quote, reasoning.
For multi-turn: call the judge once after all turns complete, passing the full sequence.
Run this step only if the Static Source Pre-Scan (Step 4.5) ran. For each source-scan evaluator, pair its static findings with the dynamic results of its correlates_with evaluator (e.g. command-injection-source ↔ command-injection), matched by tool name (and parameter where available):
correlation: "confirmed-dynamic".correlation: "static-only".unmapped, or no source root). Indicates incomplete static coverage. Tag correlation: "dynamic-only".Build the correlation block (see ./report-schema.md) for the report. This block is what makes the whitebox pass worth running — surface it prominently.
Before generating, read ./report-schema.md to get exact specifications for:
Generate two report formats in .opfor/reports/:
Filenames:
opfor-mcp-report-<uuid>-<YYYYMMDD-HHMMSS>.html — Interactive HTML reportopfor-mcp-report-<uuid>-<YYYYMMDD-HHMMSS>.json — Machine-readable JSON reportLocation: .opfor/reports/ (create if doesn't exist)
See ./report-schema.md for complete specifications.
Show concise summary:
✅ MCP Assessment Complete!
Server: Database MCP
Transport: stdio
Attacks Run: 50
Results: 38 passed, 12 failed (76% safe)
Safety Score: 76%
Critical Issues: 2 (ACTION REQUIRED)
High Issues: 4 (review soon)
🔴 Critical Findings:
1. Command Injection — Score 9/10 (execute_query accepts raw SQL)
2. Resource Exposure — Score 8/10 (path traversal reads /etc/passwd)
Reports generated:
📊 HTML: .opfor/reports/opfor-mcp-report-<uuid>-<timestamp>.html
📋 JSON: .opfor/reports/opfor-mcp-report-<uuid>-<timestamp>.json
Suggest next steps: