diff --git a/src/features/AGENTS.md b/src/features/AGENTS.md index 1d2ec6c09..ee7bc82fb 100644 --- a/src/features/AGENTS.md +++ b/src/features/AGENTS.md @@ -16,7 +16,7 @@ File counts are NON-TEST `.ts` files only (test files co-located but excluded fr | **background-agent** | 30 / 1 subdir (spawner/) | HIGH | yes | Task lifecycle, concurrency (5/key), 3s polling, spawner pattern, circuit breaker. Newer files: `parent-wake-notifier.ts` (587 LOC), `loop-detector`, `error-classifier`, `fallback-retry-handler`, `process-cleanup`, `subagent-spawn-limits`, `session-status-classifier`, `compaction-aware-message-resolver`. | | **tmux-subagent** | 27 | HIGH | yes | Tmux pane management, grid planning, session orchestration via `runTmuxCommand` | | **opencode-skill-loader** | 25 / 1 subdir (merger/) | HIGH | yes | YAML frontmatter skill discovery from 4 scopes (project > opencode > user > global) | -| **builtin-skills** | 19 / 5 subdirs | LOW–MED | yes | 11 built-in skill files (git-master, playwright, frontend-ui-ux, review-work, ai-slop-remover, security-review, dev-browser, playwright-cli, **team-mode**, …) | +| **builtin-skills** | 20 / 6 subdirs | LOW–MED | yes | 12 built-in skill files (git-master, playwright, frontend-ui-ux, review-work, ai-slop-remover, security-research, security-review, dev-browser, playwright-cli, **team-mode**, …) | | **skill-mcp-manager** | 11 | HIGH | yes | Tier-3 MCP client lifecycle per session (stdio + HTTP + OAuth) | | **claude-code-plugin-loader** | 11 | MEDIUM | yes | Unified Claude Code plugin discovery (commands, agents, skills, hooks, MCPs) | | **builtin-commands** | 11 / 1 subdir (templates/) | LOW | yes | Command templates: refactor, init-deep, handoff, ulw-loop, etc. | @@ -70,7 +70,7 @@ Eligible members: sisyphus, atlas, sisyphus-junior, hephaestus only. See [`team- State-first tmux integration. Centralized tmux command execution through `src/shared/tmux/runner.ts` (`runTmuxCommand`). Direct `Bun.spawn(["tmux", ...])` is FORBIDDEN — would drift from retry/timeout discipline. -### builtin-skills (11 skills) +### builtin-skills (12 skills) | Skill | LOC | MCP | Notes | |-------|-----|-----|-------| @@ -80,7 +80,8 @@ State-first tmux integration. Centralized tmux command execution through `src/sh | dev-browser | 221 | — | Persistent page state browser | | review-work | ~500 | — | 5-agent post-implementation review orchestrator | | ai-slop-remover | ~300 | — | Remove AI code patterns | -| security-review | ~180 | — | Team Mode exploitability-driven security review | +| security-research | SKILL.md | — | Team Mode exploitability-driven security research | +| security-review | wrapper | — | Alias for security-research | | **team-mode** | — | — | Loaded only when `team_mode.enabled` (skill explains the 12 tools to agents) | | frontend-ui-ux | 79 | — | Design-first UI development | | (git-master-skill-metadata) | — | — | Companion to git-master | diff --git a/src/features/builtin-skills/AGENTS.md b/src/features/builtin-skills/AGENTS.md index 37e204ab8..1aa1f464f 100644 --- a/src/features/builtin-skills/AGENTS.md +++ b/src/features/builtin-skills/AGENTS.md @@ -1,4 +1,4 @@ -# src/features/builtin-skills/ — 11 Built-in Skill Files +# src/features/builtin-skills/ — 12 Built-in Skill Files **Generated:** 2026-05-15 @@ -11,7 +11,7 @@ Skills shipped inside the plugin (always available, no install). Registered via ``` builtin-skills/ ├── index.ts # Barrel exports -├── skills.ts # createBuiltinSkills() factory — registers all 11 below +├── skills.ts # createBuiltinSkills() factory — registers all 12 below ├── types.ts # BuiltinSkill interface ├── skills/ │ ├── git-master.ts # 1111 LOC @@ -23,13 +23,15 @@ builtin-skills/ │ ├── review-work.ts # 5-agent post-implementation review │ ├── ai-slop-remover.ts # Remove AI-generated code patterns │ ├── team-mode.ts # 12 team_* tool documentation (gated) -│ ├── security-review.ts # Team Mode exploitability-driven security review +│ ├── security-research.ts # Team Mode exploitability-driven security research +│ ├── security-review.ts # Alias for security-research │ ├── git-master-sections/ # Git-master prompt sub-sections │ └── index.ts # skill barrel ├── git-master/ # Resources for git-master skill ├── frontend-ui-ux/ # Resources for frontend-ui-ux skill ├── agent-browser/ # Resources for agent-browser variant -└── dev-browser/ # Resources for dev-browser +├── dev-browser/ # Resources for dev-browser +└── security-research/ # Resources for security-research ``` ## SKILL CATALOG @@ -44,7 +46,8 @@ builtin-skills/ | `frontend-ui-ux` | 79 | — | Design-first UI development guidance | | `review-work` | ~500 | — | Post-implementation review orchestrator (5 parallel agents) | | `ai-slop-remover` | ~300 | — | Remove AI-generated code smells | -| `security-review` | ~180 | — | Team Mode exploitability-driven security review | +| `security-research` | SKILL.md | — | Team Mode exploitability-driven security research | +| `security-review` | wrapper | — | Alias for `security-research` | | `team-mode` | — | — | **Conditional** — only loaded when `team_mode.enabled`; documents the 12 `team_*` tools and lifecycle | ## BROWSER VARIANT SELECTION diff --git a/src/features/builtin-skills/security-research/SKILL.md b/src/features/builtin-skills/security-research/SKILL.md new file mode 100644 index 000000000..35fe81a61 --- /dev/null +++ b/src/features/builtin-skills/security-research/SKILL.md @@ -0,0 +1,198 @@ +# Security Research - Team Mode Vulnerability Audit + +Use this skill to run a parallel security audit that separates real exploitability from generic concern. The team has 3 vulnerability hunters and 2 PoC engineers. + +## Hard Preconditions + +Before starting, verify: + +1. `team_*` tools are available. If not, stop and tell the user: + `security-research requires team-mode. Set team_mode.enabled: true in your oh-my-openagent config, restart opencode, then retry.` +2. You are in the main session, not a background subagent. +3. You have a concrete target: repository, diff range, PR, release candidate, path list, or threat surface. + +If the user provided no target, audit the current repository and current branch diff against its upstream or merge base. If there is no diff, audit the security-sensitive surfaces in the working tree. + +## Severity Standard + +Use these references as the scoring frame: + +- CWE for root-cause weakness classification: https://cwe.mitre.org/ +- OWASP WSTG for test methodology: https://devguide.owasp.org/en/06-verification/01-guides/01-wstg/ +- OWASP ASVS for control verification: https://owasp.org/www-project-application-security-verification-standard/ +- CVSS v4.0 for exploitability and impact scoring: https://www.first.org/cvss/v4.0/specification-document + +Rules: + +- No severity without an attack path. +- No critical or high finding without concrete exploit preconditions and impact. +- Keep CWE category separate from severity. +- Prefer a small, reproducible PoC over theoretical language. +- Never run destructive exploits against real services or third-party systems. +- Use local fixtures, toy payloads, dry runs, or static proof when real execution would be unsafe. + +## Team Roster + +Create one Team Mode run with these 5 members: + +| Member | Kind | Category | Role | +|--------|------|----------|------| +| `surface-hunter` | category | `deep` | Map entry points, trust boundaries, and reachable attack surfaces. | +| `auth-data-hunter` | category | `ultrabrain` | Hunt auth, authorization, data isolation, injection, and secret handling flaws. | +| `runtime-supply-hunter` | category | `unspecified-high` | Hunt filesystem, subprocess, archive, dependency, hook, MCP, and config risks. | +| `poc-engineer-a` | category | `unspecified-high` | Build minimal PoCs for the strongest candidate findings. | +| `poc-engineer-b` | category | `deep` | Independently reproduce, falsify, or downgrade candidate findings. | + +Call `team_create` with an inline spec: + +```typescript +team_create({ + inline_spec: { + name: "security-research", + description: "Parallel exploitability-driven security research team.", + members: [ + { + name: "surface-hunter", + kind: "category", + category: "deep", + prompt: "You map attack surface. Enumerate entry points, trust boundaries, attacker-controlled inputs, data sinks, privilege transitions, and sensitive assets. Return evidence with file paths and exact functions. Do not assign severity unless you can name an attack path." + }, + { + name: "auth-data-hunter", + kind: "category", + category: "ultrabrain", + prompt: "You hunt auth, authorization, tenant/data isolation, injection, SSRF, credential exposure, and confused-deputy flaws. Reason from attacker capability to impact. Return only findings with concrete exploit preconditions, CWE candidates, and verification steps." + }, + { + name: "runtime-supply-hunter", + kind: "category", + category: "unspecified-high", + prompt: "You hunt filesystem, subprocess, archive extraction, dependency, hook execution, MCP, config, and environment-variable risks. Check path traversal, command injection, unsafe downloads, permission boundaries, and supply-chain assumptions. Cite file paths and commands used." + }, + { + name: "poc-engineer-a", + kind: "category", + category: "unspecified-high", + prompt: "You build minimal safe PoCs for candidate findings. Use toy inputs and local-only execution. Your job is to prove or disprove exploitability, not to broaden scope. Report exact reproduction steps and expected output." + }, + { + name: "poc-engineer-b", + kind: "category", + category: "deep", + prompt: "You independently reproduce candidate findings and try to falsify them. Downgrade anything without a working path. If a PoC is unsafe to run, design a safe static or dry-run proof and explain the limit." + } + ] + } +}) +``` + +If a category is unavailable, retry once by replacing only that category with `unspecified-high`. Do not reduce the team below 5 members. + +## Workflow + +### Phase 0: Scope and Baseline + +Collect: + +- Target scope and reason for audit. +- Branch, base ref, diff, and changed files if this is a change review. +- Security-sensitive directories and files if this is a full-repo audit. +- Existing tests and commands that exercise relevant surfaces. +- Any user-stated constraints, such as no network calls or no destructive tests. + +Use `rg`, `git diff`, `git log`, LSP, and existing tests before assigning work. + +### Phase 1: Independent Hunter Pass + +Send one prompt to the 3 hunters: + +```text +Audit target: +{target summary} + +Context: +{diff, file list, security-sensitive paths, known constraints} + +Task: +Find candidate vulnerabilities in your assigned role. For each candidate include: +- title +- affected file/function +- attacker capability +- attack path +- impact +- CWE candidate +- exact evidence +- safe verification idea + +Reject generic hardening advice. Return only candidates with a plausible path. +``` + +Wait for all hunters. + +### Phase 2: PoC Pass + +Deduplicate hunter candidates. Send the strongest candidates to both PoC engineers. + +Each PoC engineer must return: + +- Reproduced, falsified, or unsafe-to-run. +- Exact commands, fixtures, or static proof. +- Observed output or reason it fails. +- Severity recommendation using exploitability and impact. +- Downgrade rationale for anything not reproduced. + +### Phase 3: Cross-Check + +Send the PoC results back to all 5 members. + +Ask every member: + +- Which findings survive? +- Which findings should be downgraded or removed? +- What remediation is smallest and specific? +- What regression test would prevent recurrence? + +### Phase 4: Final Report + +Produce this report: + +```markdown +## Security Research Result + +### Verdict +PASS | PASS WITH FINDINGS | BLOCK + +### Scope +- Target: +- Base/diff: +- Commands run: + +### Findings +| Severity | Title | CWE | Exploitability | Impact | PoC | Fix | +|----------|-------|-----|----------------|--------|-----|-----| + +### Finding Details +For each finding: +- Evidence: +- Attack path: +- PoC: +- Severity rationale: +- Minimal fix: +- Regression check: + +### Downgraded or Rejected Candidates +| Candidate | Reason | +|-----------|--------| + +### Residual Risk +- What was not tested and why. +``` + +## Output Rules + +- Lead with the verdict. +- Do not bury blocking issues. +- Do not report speculative findings as vulnerabilities. +- Do not claim CVSS precision unless you actually scored the metrics. +- Include exact file paths and commands for every surviving finding. +- If no findings survive PoC, say that plainly and list residual risk. diff --git a/src/features/builtin-skills/skills.test.ts b/src/features/builtin-skills/skills.test.ts index ab9614b60..2b6da682e 100644 --- a/src/features/builtin-skills/skills.test.ts +++ b/src/features/builtin-skills/skills.test.ts @@ -13,8 +13,8 @@ describe("createBuiltinSkills", () => { // then const browserSkill = skills.find((s) => s.name === "playwright") expect(browserSkill).toBeDefined() - expect(browserSkill!.description).toContain("browser") - expect(browserSkill!.mcpConfig?.playwright).toBeDefined() + expect(browserSkill?.description).toContain("browser") + expect(browserSkill?.mcpConfig?.playwright).toBeDefined() }) test("returns playwright skill when browserProvider is 'playwright'", () => { @@ -46,7 +46,7 @@ describe("createBuiltinSkills", () => { const playwrightSkill = skills.find((skill) => skill.name === "playwright") const agentBrowserSkill = skills.find((skill) => skill.name === "agent-browser") expect(devBrowserSkill).toBeDefined() - expect(devBrowserSkill!.description).toContain("Browser automation") + expect(devBrowserSkill?.description).toContain("Browser automation") expect(playwrightSkill).toBeUndefined() expect(agentBrowserSkill).toBeUndefined() expect(skillNames).not.toContain("playwright-cli") @@ -64,9 +64,9 @@ describe("createBuiltinSkills", () => { const agentBrowserSkill = skills.find((s) => s.name === "agent-browser") const playwrightSkill = skills.find((s) => s.name === "playwright") expect(agentBrowserSkill).toBeDefined() - expect(agentBrowserSkill!.description).toContain("browser") - expect(agentBrowserSkill!.allowedTools).toContain("Bash(agent-browser:*)") - expect(agentBrowserSkill!.template).toContain("agent-browser") + expect(agentBrowserSkill?.description).toContain("browser") + expect(agentBrowserSkill?.allowedTools).toContain("Bash(agent-browser:*)") + expect(agentBrowserSkill?.template).toContain("agent-browser") expect(playwrightSkill).toBeUndefined() }) @@ -79,13 +79,13 @@ describe("createBuiltinSkills", () => { const agentBrowserSkill = skills.find((s) => s.name === "agent-browser") // then - template should contain substantial content (inlined, not fallback) - expect(agentBrowserSkill!.template).toContain("## Quick start") - expect(agentBrowserSkill!.template).toContain("## Commands") - expect(agentBrowserSkill!.template).toContain("agent-browser open") - expect(agentBrowserSkill!.template).toContain("agent-browser snapshot") + expect(agentBrowserSkill?.template).toContain("## Quick start") + expect(agentBrowserSkill?.template).toContain("## Commands") + expect(agentBrowserSkill?.template).toContain("agent-browser open") + expect(agentBrowserSkill?.template).toContain("agent-browser snapshot") }) - test("always includes frontend-ui-ux, git-master, review-work, ai-slop-remover, and security-review skills", () => { + test("always includes frontend-ui-ux, git-master, review-work, ai-slop-remover, security-research, and security-review skills", () => { // given - both provider options // when @@ -99,11 +99,12 @@ describe("createBuiltinSkills", () => { expect(skills.find((s) => s.name === "git-master")).toBeDefined() expect(skills.find((s) => s.name === "review-work")).toBeDefined() expect(skills.find((s) => s.name === "ai-slop-remover")).toBeDefined() + expect(skills.find((s) => s.name === "security-research")).toBeDefined() expect(skills.find((s) => s.name === "security-review")).toBeDefined() } }) - test("returns exactly 6 skills regardless of provider", () => { + test("returns exactly 7 skills regardless of provider", () => { // given // when @@ -112,9 +113,9 @@ describe("createBuiltinSkills", () => { const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" }) // then - expect(defaultSkills).toHaveLength(6) - expect(agentBrowserSkills).toHaveLength(6) - expect(devBrowserSkills).toHaveLength(6) + expect(defaultSkills).toHaveLength(7) + expect(agentBrowserSkills).toHaveLength(7) + expect(devBrowserSkills).toHaveLength(7) }) test("should exclude playwright when it is in disabledSkills", () => { @@ -131,8 +132,9 @@ describe("createBuiltinSkills", () => { expect(skills.map((s) => s.name)).not.toContain("dev-browser") expect(skills.map((s) => s.name)).toContain("review-work") expect(skills.map((s) => s.name)).toContain("ai-slop-remover") + expect(skills.map((s) => s.name)).toContain("security-research") expect(skills.map((s) => s.name)).toContain("security-review") - expect(skills.length).toBe(5) + expect(skills.length).toBe(6) }) test("should exclude multiple skills when they are in disabledSkills", () => { @@ -149,13 +151,14 @@ describe("createBuiltinSkills", () => { expect(skills.map((s) => s.name)).not.toContain("dev-browser") expect(skills.map((s) => s.name)).toContain("review-work") expect(skills.map((s) => s.name)).toContain("ai-slop-remover") + expect(skills.map((s) => s.name)).toContain("security-research") expect(skills.map((s) => s.name)).toContain("security-review") - expect(skills.length).toBe(4) + expect(skills.length).toBe(5) }) test("should return an empty array when all skills are disabled", () => { // #given - const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover", "security-review"]) } + const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover", "security-research", "security-review"]) } // #when const skills = createBuiltinSkills(options) @@ -172,7 +175,7 @@ describe("createBuiltinSkills", () => { const skills = createBuiltinSkills(options) // #then - expect(skills.length).toBe(6) + expect(skills.length).toBe(7) }) test("review-work skill has correct structure", () => { @@ -184,13 +187,13 @@ describe("createBuiltinSkills", () => { // #then expect(reviewWork).toBeDefined() - expect(reviewWork!.description).toContain("review") - expect(reviewWork!.template).toContain("5-Agent Parallel Review Orchestrator") - expect(reviewWork!.template).toContain("Goal & Constraint Verification") - expect(reviewWork!.template).toContain("QA") - expect(reviewWork!.template).toContain("Code Quality") - expect(reviewWork!.template).toContain("Security") - expect(reviewWork!.template).toContain("Context Mining") + expect(reviewWork?.description).toContain("review") + expect(reviewWork?.template).toContain("5-Agent Parallel Review Orchestrator") + expect(reviewWork?.template).toContain("Goal & Constraint Verification") + expect(reviewWork?.template).toContain("QA") + expect(reviewWork?.template).toContain("Code Quality") + expect(reviewWork?.template).toContain("Security") + expect(reviewWork?.template).toContain("Context Mining") }) test("review-work skill explains Codex tool compatibility before OpenCode orchestration examples", () => { @@ -199,8 +202,9 @@ describe("createBuiltinSkills", () => { // #when const reviewWork = skills.find((s) => s.name === "review-work") - const compatibilityIndex = reviewWork!.template.indexOf("## Codex Harness Tool Compatibility") - const opencodeExampleIndex = reviewWork!.template.search(/\b(?:background_output|team_[a-z_]+|task)\s*\(/) + const reviewWorkTemplate = reviewWork?.template ?? "" + const compatibilityIndex = reviewWorkTemplate.indexOf("## Codex Harness Tool Compatibility") + const opencodeExampleIndex = reviewWorkTemplate.search(/\b(?:background_output|team_[a-z_]+|task)\s*\(/) // #then expect(compatibilityIndex >= 0).toBe(true) @@ -216,23 +220,36 @@ describe("createBuiltinSkills", () => { // #then expect(aiSlopRemover).toBeDefined() - expect(aiSlopRemover!.description).toContain("AI-generated code smells") - expect(aiSlopRemover!.template).toContain("DETECTION CRITERIA") - expect(aiSlopRemover!.template).toContain("SAFETY RULES") + expect(aiSlopRemover?.description).toContain("AI-generated code smells") + expect(aiSlopRemover?.template).toContain("DETECTION CRITERIA") + expect(aiSlopRemover?.template).toContain("SAFETY RULES") }) - test("security-review skill has correct structure", () => { + test("security-research skill has correct structure", () => { + // #given - default options + + // #when + const skills = createBuiltinSkills() + const securityResearch = skills.find((skill) => skill.name === "security-research") + + // #then + expect(securityResearch?.description).toContain("security research") + expect(securityResearch?.template).toContain("Security Research - Team Mode Vulnerability Audit") + expect(securityResearch?.template).toContain('name: "security-research"') + expect(securityResearch?.template).toContain("Security Research Result") + }) + + test("security-review skill remains a runtime alias for security-research", () => { // #given - default options // #when const skills = createBuiltinSkills() const securityReview = skills.find((skill) => skill.name === "security-review") + const securityResearch = skills.find((skill) => skill.name === "security-research") // #then - expect(securityReview?.description).toContain("security review") - expect(securityReview?.template).toContain("Team Mode Vulnerability Audit") - expect(securityReview?.template).toContain("team_create") - expect(securityReview?.template).toContain("Security Review Result") + expect(securityReview?.description).toContain("Alias for security-research") + expect(securityReview?.template).toBe(securityResearch?.template) }) test("returns playwright-cli skill when browserProvider is 'playwright-cli'", () => { @@ -246,9 +263,9 @@ describe("createBuiltinSkills", () => { const playwrightSkill = skills.find((s) => s.name === "playwright") const agentBrowserSkill = skills.find((s) => s.name === "agent-browser") expect(playwrightSkill).toBeDefined() - expect(playwrightSkill!.description).toContain("browser") - expect(playwrightSkill!.allowedTools).toContain("Bash(playwright-cli:*)") - expect(playwrightSkill!.mcpConfig).toBeUndefined() + expect(playwrightSkill?.description).toContain("browser") + expect(playwrightSkill?.allowedTools).toContain("Bash(playwright-cli:*)") + expect(playwrightSkill?.mcpConfig).toBeUndefined() expect(agentBrowserSkill).toBeUndefined() }) @@ -261,8 +278,8 @@ describe("createBuiltinSkills", () => { const skill = skills.find((s) => s.name === "playwright") // then - expect(skill!.template).toContain("playwright-cli open") - expect(skill!.template).toContain("playwright-cli snapshot") - expect(skill!.template).toContain("playwright-cli click") + expect(skill?.template).toContain("playwright-cli open") + expect(skill?.template).toContain("playwright-cli snapshot") + expect(skill?.template).toContain("playwright-cli click") }) }) diff --git a/src/features/builtin-skills/skills.ts b/src/features/builtin-skills/skills.ts index edd02853e..f4c4c60cf 100644 --- a/src/features/builtin-skills/skills.ts +++ b/src/features/builtin-skills/skills.ts @@ -10,6 +10,7 @@ import { devBrowserSkill, reviewWorkSkill, aiSlopRemoverSkill, + securityResearchSkill, securityReviewSkill, teamModeSkill, } from "./skills/index" @@ -40,6 +41,7 @@ export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): B gitMasterSkill, reviewWorkSkill, aiSlopRemoverSkill, + securityResearchSkill, securityReviewSkill, ] diff --git a/src/features/builtin-skills/skills/index.ts b/src/features/builtin-skills/skills/index.ts index cbec60a18..736b64831 100644 --- a/src/features/builtin-skills/skills/index.ts +++ b/src/features/builtin-skills/skills/index.ts @@ -5,5 +5,6 @@ export { gitMasterSkill } from "./git-master" export { devBrowserSkill } from "./dev-browser" export { reviewWorkSkill } from "./review-work" export { aiSlopRemoverSkill } from "./ai-slop-remover" +export { securityResearchSkill } from "./security-research" export { securityReviewSkill } from "./security-review" export * from "./team-mode" diff --git a/src/features/builtin-skills/skills/security-research.ts b/src/features/builtin-skills/skills/security-research.ts new file mode 100644 index 000000000..f190bf13b --- /dev/null +++ b/src/features/builtin-skills/skills/security-research.ts @@ -0,0 +1,9 @@ +import type { BuiltinSkill } from "../types" +import securityResearchTemplate from "../security-research/SKILL.md" with { type: "text" } + +export const securityResearchSkill: BuiltinSkill = { + name: "security-research", + description: + "Team Mode security research skill. Orchestrates 3 vulnerability hunters and 2 PoC engineers to audit a codebase in parallel, prove exploitability, classify root causes, and calibrate severity by actual exploitability. Use for security review, vulnerability research, exploitability audit, pre-release security check, threat model validation, and `/security-research`. Triggers: 'security-research', 'security research', 'security review', 'vulnerability audit', 'exploitability audit', '보안 리뷰', '취약점 감사'.", + template: securityResearchTemplate, +} diff --git a/src/features/builtin-skills/skills/security-review.ts b/src/features/builtin-skills/skills/security-review.ts index 695a27957..7a77d2b60 100644 --- a/src/features/builtin-skills/skills/security-review.ts +++ b/src/features/builtin-skills/skills/security-review.ts @@ -1,206 +1,8 @@ import type { BuiltinSkill } from "../types" +import { securityResearchSkill } from "./security-research" export const securityReviewSkill: BuiltinSkill = { name: "security-review", - description: - "Team Mode security review skill. Orchestrates 3 vulnerability hunters and 2 PoC engineers to audit a codebase in parallel, prove exploitability, classify root causes, and calibrate severity by actual exploitability. Use for security review, vulnerability research, exploitability audit, pre-release security check, threat model validation, and `/security-review`. Triggers: 'security-review', 'security review', 'security research', 'vulnerability audit', 'exploitability audit', '보안 리뷰', '취약점 감사'.", - template: `# Security Review - Team Mode Vulnerability Audit - -Use this skill to run a parallel security audit that separates real exploitability from generic concern. The team has 3 vulnerability hunters and 2 PoC engineers. - -## Hard Preconditions - -Before starting, verify: - -1. \`team_*\` tools are available. If not, stop and tell the user: - \`security-review requires team-mode. Set team_mode.enabled: true in your oh-my-openagent config, restart opencode, then retry.\` -2. You are in the main session, not a background subagent. -3. You have a concrete target: repository, diff range, PR, release candidate, path list, or threat surface. - -If the user provided no target, audit the current repository and current branch diff against its upstream or merge base. If there is no diff, audit the security-sensitive surfaces in the working tree. - -## Severity Standard - -Use these references as the scoring frame: - -- CWE for root-cause weakness classification: https://cwe.mitre.org/ -- OWASP WSTG for test methodology: https://devguide.owasp.org/en/06-verification/01-guides/01-wstg/ -- OWASP ASVS for control verification: https://owasp.org/www-project-application-security-verification-standard/ -- CVSS v4.0 for exploitability and impact scoring: https://www.first.org/cvss/v4.0/specification-document - -Rules: - -- No severity without an attack path. -- No critical or high finding without concrete exploit preconditions and impact. -- Keep CWE category separate from severity. -- Prefer a small, reproducible PoC over theoretical language. -- Never run destructive exploits against real services or third-party systems. -- Use local fixtures, toy payloads, dry runs, or static proof when real execution would be unsafe. - -## Team Roster - -Create one Team Mode run with these 5 members: - -| Member | Kind | Category | Role | -|--------|------|----------|------| -| \`surface-hunter\` | category | \`deep\` | Map entry points, trust boundaries, and reachable attack surfaces. | -| \`auth-data-hunter\` | category | \`ultrabrain\` | Hunt auth, authorization, data isolation, injection, and secret handling flaws. | -| \`runtime-supply-hunter\` | category | \`unspecified-high\` | Hunt filesystem, subprocess, archive, dependency, hook, MCP, and config risks. | -| \`poc-engineer-a\` | category | \`unspecified-high\` | Build minimal PoCs for the strongest candidate findings. | -| \`poc-engineer-b\` | category | \`deep\` | Independently reproduce, falsify, or downgrade candidate findings. | - -Call \`team_create\` with an inline spec: - -\`\`\`typescript -team_create({ - inline_spec: { - name: "security-review", - description: "Parallel exploitability-driven security review team.", - members: [ - { - name: "surface-hunter", - kind: "category", - category: "deep", - prompt: "You map attack surface. Enumerate entry points, trust boundaries, attacker-controlled inputs, data sinks, privilege transitions, and sensitive assets. Return evidence with file paths and exact functions. Do not assign severity unless you can name an attack path." - }, - { - name: "auth-data-hunter", - kind: "category", - category: "ultrabrain", - prompt: "You hunt auth, authorization, tenant/data isolation, injection, SSRF, credential exposure, and confused-deputy flaws. Reason from attacker capability to impact. Return only findings with concrete exploit preconditions, CWE candidates, and verification steps." - }, - { - name: "runtime-supply-hunter", - kind: "category", - category: "unspecified-high", - prompt: "You hunt filesystem, subprocess, archive extraction, dependency, hook execution, MCP, config, and environment-variable risks. Check path traversal, command injection, unsafe downloads, permission boundaries, and supply-chain assumptions. Cite file paths and commands used." - }, - { - name: "poc-engineer-a", - kind: "category", - category: "unspecified-high", - prompt: "You build minimal safe PoCs for candidate findings. Use toy inputs and local-only execution. Your job is to prove or disprove exploitability, not to broaden scope. Report exact reproduction steps and expected output." - }, - { - name: "poc-engineer-b", - kind: "category", - category: "deep", - prompt: "You independently reproduce candidate findings and try to falsify them. Downgrade anything without a working path. If a PoC is unsafe to run, design a safe static or dry-run proof and explain the limit." - } - ] - } -}) -\`\`\` - -If a category is unavailable, retry once by replacing only that category with \`unspecified-high\`. Do not reduce the team below 5 members. - -## Workflow - -### Phase 0: Scope and Baseline - -Collect: - -- Target scope and reason for audit. -- Branch, base ref, diff, and changed files if this is a change review. -- Security-sensitive directories and files if this is a full-repo audit. -- Existing tests and commands that exercise relevant surfaces. -- Any user-stated constraints, such as no network calls or no destructive tests. - -Use \`rg\`, \`git diff\`, \`git log\`, LSP, and existing tests before assigning work. - -### Phase 1: Independent Hunter Pass - -Send one prompt to the 3 hunters: - -\`\`\`text -Audit target: -{target summary} - -Context: -{diff, file list, security-sensitive paths, known constraints} - -Task: -Find candidate vulnerabilities in your assigned role. For each candidate include: -- title -- affected file/function -- attacker capability -- attack path -- impact -- CWE candidate -- exact evidence -- safe verification idea - -Reject generic hardening advice. Return only candidates with a plausible path. -\`\`\` - -Wait for all hunters. - -### Phase 2: PoC Pass - -Deduplicate hunter candidates. Send the strongest candidates to both PoC engineers. - -Each PoC engineer must return: - -- Reproduced, falsified, or unsafe-to-run. -- Exact commands, fixtures, or static proof. -- Observed output or reason it fails. -- Severity recommendation using exploitability and impact. -- Downgrade rationale for anything not reproduced. - -### Phase 3: Cross-Check - -Send the PoC results back to all 5 members. - -Ask every member: - -- Which findings survive? -- Which findings should be downgraded or removed? -- What remediation is smallest and specific? -- What regression test would prevent recurrence? - -### Phase 4: Final Report - -Produce this report: - -\`\`\`markdown -## Security Review Result - -### Verdict -PASS | PASS WITH FINDINGS | BLOCK - -### Scope -- Target: -- Base/diff: -- Commands run: - -### Findings -| Severity | Title | CWE | Exploitability | Impact | PoC | Fix | -|----------|-------|-----|----------------|--------|-----|-----| - -### Finding Details -For each finding: -- Evidence: -- Attack path: -- PoC: -- Severity rationale: -- Minimal fix: -- Regression check: - -### Downgraded or Rejected Candidates -| Candidate | Reason | -|-----------|--------| - -### Residual Risk -- What was not tested and why. -\`\`\` - -## Output Rules - -- Lead with the verdict. -- Do not bury blocking issues. -- Do not report speculative findings as vulnerabilities. -- Do not claim CVSS precision unless you actually scored the metrics. -- Include exact file paths and commands for every surviving finding. -- If no findings survive PoC, say that plainly and list residual risk. -`, + description: `Alias for security-research. ${securityResearchSkill.description}`, + template: securityResearchSkill.template, }