fix(skills): register security-research builtin
This commit is contained in:
@@ -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`. |
|
| **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` |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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. |
|
| **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.
|
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 |
|
| 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 |
|
| dev-browser | 221 | — | Persistent page state browser |
|
||||||
| review-work | ~500 | — | 5-agent post-implementation review orchestrator |
|
| review-work | ~500 | — | 5-agent post-implementation review orchestrator |
|
||||||
| ai-slop-remover | ~300 | — | Remove AI code patterns |
|
| 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) |
|
| **team-mode** | — | — | Loaded only when `team_mode.enabled` (skill explains the 12 tools to agents) |
|
||||||
| frontend-ui-ux | 79 | — | Design-first UI development |
|
| frontend-ui-ux | 79 | — | Design-first UI development |
|
||||||
| (git-master-skill-metadata) | — | — | Companion to git-master |
|
| (git-master-skill-metadata) | — | — | Companion to git-master |
|
||||||
|
|||||||
@@ -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
|
**Generated:** 2026-05-15
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ Skills shipped inside the plugin (always available, no install). Registered via
|
|||||||
```
|
```
|
||||||
builtin-skills/
|
builtin-skills/
|
||||||
├── index.ts # Barrel exports
|
├── index.ts # Barrel exports
|
||||||
├── skills.ts # createBuiltinSkills() factory — registers all 11 below
|
├── skills.ts # createBuiltinSkills() factory — registers all 12 below
|
||||||
├── types.ts # BuiltinSkill interface
|
├── types.ts # BuiltinSkill interface
|
||||||
├── skills/
|
├── skills/
|
||||||
│ ├── git-master.ts # 1111 LOC
|
│ ├── git-master.ts # 1111 LOC
|
||||||
@@ -23,13 +23,15 @@ builtin-skills/
|
|||||||
│ ├── review-work.ts # 5-agent post-implementation review
|
│ ├── review-work.ts # 5-agent post-implementation review
|
||||||
│ ├── ai-slop-remover.ts # Remove AI-generated code patterns
|
│ ├── ai-slop-remover.ts # Remove AI-generated code patterns
|
||||||
│ ├── team-mode.ts # 12 team_* tool documentation (gated)
|
│ ├── 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
|
│ ├── git-master-sections/ # Git-master prompt sub-sections
|
||||||
│ └── index.ts # skill barrel
|
│ └── index.ts # skill barrel
|
||||||
├── git-master/ # Resources for git-master skill
|
├── git-master/ # Resources for git-master skill
|
||||||
├── frontend-ui-ux/ # Resources for frontend-ui-ux skill
|
├── frontend-ui-ux/ # Resources for frontend-ui-ux skill
|
||||||
├── agent-browser/ # Resources for agent-browser variant
|
├── 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
|
## SKILL CATALOG
|
||||||
@@ -44,7 +46,8 @@ builtin-skills/
|
|||||||
| `frontend-ui-ux` | 79 | — | Design-first UI development guidance |
|
| `frontend-ui-ux` | 79 | — | Design-first UI development guidance |
|
||||||
| `review-work` | ~500 | — | Post-implementation review orchestrator (5 parallel agents) |
|
| `review-work` | ~500 | — | Post-implementation review orchestrator (5 parallel agents) |
|
||||||
| `ai-slop-remover` | ~300 | — | Remove AI-generated code smells |
|
| `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 |
|
| `team-mode` | — | — | **Conditional** — only loaded when `team_mode.enabled`; documents the 12 `team_*` tools and lifecycle |
|
||||||
|
|
||||||
## BROWSER VARIANT SELECTION
|
## BROWSER VARIANT SELECTION
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -13,8 +13,8 @@ describe("createBuiltinSkills", () => {
|
|||||||
// then
|
// then
|
||||||
const browserSkill = skills.find((s) => s.name === "playwright")
|
const browserSkill = skills.find((s) => s.name === "playwright")
|
||||||
expect(browserSkill).toBeDefined()
|
expect(browserSkill).toBeDefined()
|
||||||
expect(browserSkill!.description).toContain("browser")
|
expect(browserSkill?.description).toContain("browser")
|
||||||
expect(browserSkill!.mcpConfig?.playwright).toBeDefined()
|
expect(browserSkill?.mcpConfig?.playwright).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("returns playwright skill when browserProvider is 'playwright'", () => {
|
test("returns playwright skill when browserProvider is 'playwright'", () => {
|
||||||
@@ -46,7 +46,7 @@ describe("createBuiltinSkills", () => {
|
|||||||
const playwrightSkill = skills.find((skill) => skill.name === "playwright")
|
const playwrightSkill = skills.find((skill) => skill.name === "playwright")
|
||||||
const agentBrowserSkill = skills.find((skill) => skill.name === "agent-browser")
|
const agentBrowserSkill = skills.find((skill) => skill.name === "agent-browser")
|
||||||
expect(devBrowserSkill).toBeDefined()
|
expect(devBrowserSkill).toBeDefined()
|
||||||
expect(devBrowserSkill!.description).toContain("Browser automation")
|
expect(devBrowserSkill?.description).toContain("Browser automation")
|
||||||
expect(playwrightSkill).toBeUndefined()
|
expect(playwrightSkill).toBeUndefined()
|
||||||
expect(agentBrowserSkill).toBeUndefined()
|
expect(agentBrowserSkill).toBeUndefined()
|
||||||
expect(skillNames).not.toContain("playwright-cli")
|
expect(skillNames).not.toContain("playwright-cli")
|
||||||
@@ -64,9 +64,9 @@ describe("createBuiltinSkills", () => {
|
|||||||
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
||||||
const playwrightSkill = skills.find((s) => s.name === "playwright")
|
const playwrightSkill = skills.find((s) => s.name === "playwright")
|
||||||
expect(agentBrowserSkill).toBeDefined()
|
expect(agentBrowserSkill).toBeDefined()
|
||||||
expect(agentBrowserSkill!.description).toContain("browser")
|
expect(agentBrowserSkill?.description).toContain("browser")
|
||||||
expect(agentBrowserSkill!.allowedTools).toContain("Bash(agent-browser:*)")
|
expect(agentBrowserSkill?.allowedTools).toContain("Bash(agent-browser:*)")
|
||||||
expect(agentBrowserSkill!.template).toContain("agent-browser")
|
expect(agentBrowserSkill?.template).toContain("agent-browser")
|
||||||
expect(playwrightSkill).toBeUndefined()
|
expect(playwrightSkill).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -79,13 +79,13 @@ describe("createBuiltinSkills", () => {
|
|||||||
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
||||||
|
|
||||||
// then - template should contain substantial content (inlined, not fallback)
|
// then - template should contain substantial content (inlined, not fallback)
|
||||||
expect(agentBrowserSkill!.template).toContain("## Quick start")
|
expect(agentBrowserSkill?.template).toContain("## Quick start")
|
||||||
expect(agentBrowserSkill!.template).toContain("## Commands")
|
expect(agentBrowserSkill?.template).toContain("## Commands")
|
||||||
expect(agentBrowserSkill!.template).toContain("agent-browser open")
|
expect(agentBrowserSkill?.template).toContain("agent-browser open")
|
||||||
expect(agentBrowserSkill!.template).toContain("agent-browser snapshot")
|
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
|
// given - both provider options
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -99,11 +99,12 @@ describe("createBuiltinSkills", () => {
|
|||||||
expect(skills.find((s) => s.name === "git-master")).toBeDefined()
|
expect(skills.find((s) => s.name === "git-master")).toBeDefined()
|
||||||
expect(skills.find((s) => s.name === "review-work")).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 === "ai-slop-remover")).toBeDefined()
|
||||||
|
expect(skills.find((s) => s.name === "security-research")).toBeDefined()
|
||||||
expect(skills.find((s) => s.name === "security-review")).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
|
// given
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -112,9 +113,9 @@ describe("createBuiltinSkills", () => {
|
|||||||
const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" })
|
const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" })
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(defaultSkills).toHaveLength(6)
|
expect(defaultSkills).toHaveLength(7)
|
||||||
expect(agentBrowserSkills).toHaveLength(6)
|
expect(agentBrowserSkills).toHaveLength(7)
|
||||||
expect(devBrowserSkills).toHaveLength(6)
|
expect(devBrowserSkills).toHaveLength(7)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("should exclude playwright when it is in disabledSkills", () => {
|
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)).not.toContain("dev-browser")
|
||||||
expect(skills.map((s) => s.name)).toContain("review-work")
|
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("ai-slop-remover")
|
||||||
|
expect(skills.map((s) => s.name)).toContain("security-research")
|
||||||
expect(skills.map((s) => s.name)).toContain("security-review")
|
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", () => {
|
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)).not.toContain("dev-browser")
|
||||||
expect(skills.map((s) => s.name)).toContain("review-work")
|
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("ai-slop-remover")
|
||||||
|
expect(skills.map((s) => s.name)).toContain("security-research")
|
||||||
expect(skills.map((s) => s.name)).toContain("security-review")
|
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", () => {
|
test("should return an empty array when all skills are disabled", () => {
|
||||||
// #given
|
// #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
|
// #when
|
||||||
const skills = createBuiltinSkills(options)
|
const skills = createBuiltinSkills(options)
|
||||||
@@ -172,7 +175,7 @@ describe("createBuiltinSkills", () => {
|
|||||||
const skills = createBuiltinSkills(options)
|
const skills = createBuiltinSkills(options)
|
||||||
|
|
||||||
// #then
|
// #then
|
||||||
expect(skills.length).toBe(6)
|
expect(skills.length).toBe(7)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("review-work skill has correct structure", () => {
|
test("review-work skill has correct structure", () => {
|
||||||
@@ -184,13 +187,13 @@ describe("createBuiltinSkills", () => {
|
|||||||
|
|
||||||
// #then
|
// #then
|
||||||
expect(reviewWork).toBeDefined()
|
expect(reviewWork).toBeDefined()
|
||||||
expect(reviewWork!.description).toContain("review")
|
expect(reviewWork?.description).toContain("review")
|
||||||
expect(reviewWork!.template).toContain("5-Agent Parallel Review Orchestrator")
|
expect(reviewWork?.template).toContain("5-Agent Parallel Review Orchestrator")
|
||||||
expect(reviewWork!.template).toContain("Goal & Constraint Verification")
|
expect(reviewWork?.template).toContain("Goal & Constraint Verification")
|
||||||
expect(reviewWork!.template).toContain("QA")
|
expect(reviewWork?.template).toContain("QA")
|
||||||
expect(reviewWork!.template).toContain("Code Quality")
|
expect(reviewWork?.template).toContain("Code Quality")
|
||||||
expect(reviewWork!.template).toContain("Security")
|
expect(reviewWork?.template).toContain("Security")
|
||||||
expect(reviewWork!.template).toContain("Context Mining")
|
expect(reviewWork?.template).toContain("Context Mining")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("review-work skill explains Codex tool compatibility before OpenCode orchestration examples", () => {
|
test("review-work skill explains Codex tool compatibility before OpenCode orchestration examples", () => {
|
||||||
@@ -199,8 +202,9 @@ describe("createBuiltinSkills", () => {
|
|||||||
|
|
||||||
// #when
|
// #when
|
||||||
const reviewWork = skills.find((s) => s.name === "review-work")
|
const reviewWork = skills.find((s) => s.name === "review-work")
|
||||||
const compatibilityIndex = reviewWork!.template.indexOf("## Codex Harness Tool Compatibility")
|
const reviewWorkTemplate = reviewWork?.template ?? ""
|
||||||
const opencodeExampleIndex = reviewWork!.template.search(/\b(?:background_output|team_[a-z_]+|task)\s*\(/)
|
const compatibilityIndex = reviewWorkTemplate.indexOf("## Codex Harness Tool Compatibility")
|
||||||
|
const opencodeExampleIndex = reviewWorkTemplate.search(/\b(?:background_output|team_[a-z_]+|task)\s*\(/)
|
||||||
|
|
||||||
// #then
|
// #then
|
||||||
expect(compatibilityIndex >= 0).toBe(true)
|
expect(compatibilityIndex >= 0).toBe(true)
|
||||||
@@ -216,23 +220,36 @@ describe("createBuiltinSkills", () => {
|
|||||||
|
|
||||||
// #then
|
// #then
|
||||||
expect(aiSlopRemover).toBeDefined()
|
expect(aiSlopRemover).toBeDefined()
|
||||||
expect(aiSlopRemover!.description).toContain("AI-generated code smells")
|
expect(aiSlopRemover?.description).toContain("AI-generated code smells")
|
||||||
expect(aiSlopRemover!.template).toContain("DETECTION CRITERIA")
|
expect(aiSlopRemover?.template).toContain("DETECTION CRITERIA")
|
||||||
expect(aiSlopRemover!.template).toContain("SAFETY RULES")
|
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
|
// #given - default options
|
||||||
|
|
||||||
// #when
|
// #when
|
||||||
const skills = createBuiltinSkills()
|
const skills = createBuiltinSkills()
|
||||||
const securityReview = skills.find((skill) => skill.name === "security-review")
|
const securityReview = skills.find((skill) => skill.name === "security-review")
|
||||||
|
const securityResearch = skills.find((skill) => skill.name === "security-research")
|
||||||
|
|
||||||
// #then
|
// #then
|
||||||
expect(securityReview?.description).toContain("security review")
|
expect(securityReview?.description).toContain("Alias for security-research")
|
||||||
expect(securityReview?.template).toContain("Team Mode Vulnerability Audit")
|
expect(securityReview?.template).toBe(securityResearch?.template)
|
||||||
expect(securityReview?.template).toContain("team_create")
|
|
||||||
expect(securityReview?.template).toContain("Security Review Result")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("returns playwright-cli skill when browserProvider is 'playwright-cli'", () => {
|
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 playwrightSkill = skills.find((s) => s.name === "playwright")
|
||||||
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
|
||||||
expect(playwrightSkill).toBeDefined()
|
expect(playwrightSkill).toBeDefined()
|
||||||
expect(playwrightSkill!.description).toContain("browser")
|
expect(playwrightSkill?.description).toContain("browser")
|
||||||
expect(playwrightSkill!.allowedTools).toContain("Bash(playwright-cli:*)")
|
expect(playwrightSkill?.allowedTools).toContain("Bash(playwright-cli:*)")
|
||||||
expect(playwrightSkill!.mcpConfig).toBeUndefined()
|
expect(playwrightSkill?.mcpConfig).toBeUndefined()
|
||||||
expect(agentBrowserSkill).toBeUndefined()
|
expect(agentBrowserSkill).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -261,8 +278,8 @@ describe("createBuiltinSkills", () => {
|
|||||||
const skill = skills.find((s) => s.name === "playwright")
|
const skill = skills.find((s) => s.name === "playwright")
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(skill!.template).toContain("playwright-cli open")
|
expect(skill?.template).toContain("playwright-cli open")
|
||||||
expect(skill!.template).toContain("playwright-cli snapshot")
|
expect(skill?.template).toContain("playwright-cli snapshot")
|
||||||
expect(skill!.template).toContain("playwright-cli click")
|
expect(skill?.template).toContain("playwright-cli click")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
devBrowserSkill,
|
devBrowserSkill,
|
||||||
reviewWorkSkill,
|
reviewWorkSkill,
|
||||||
aiSlopRemoverSkill,
|
aiSlopRemoverSkill,
|
||||||
|
securityResearchSkill,
|
||||||
securityReviewSkill,
|
securityReviewSkill,
|
||||||
teamModeSkill,
|
teamModeSkill,
|
||||||
} from "./skills/index"
|
} from "./skills/index"
|
||||||
@@ -40,6 +41,7 @@ export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): B
|
|||||||
gitMasterSkill,
|
gitMasterSkill,
|
||||||
reviewWorkSkill,
|
reviewWorkSkill,
|
||||||
aiSlopRemoverSkill,
|
aiSlopRemoverSkill,
|
||||||
|
securityResearchSkill,
|
||||||
securityReviewSkill,
|
securityReviewSkill,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ export { gitMasterSkill } from "./git-master"
|
|||||||
export { devBrowserSkill } from "./dev-browser"
|
export { devBrowserSkill } from "./dev-browser"
|
||||||
export { reviewWorkSkill } from "./review-work"
|
export { reviewWorkSkill } from "./review-work"
|
||||||
export { aiSlopRemoverSkill } from "./ai-slop-remover"
|
export { aiSlopRemoverSkill } from "./ai-slop-remover"
|
||||||
|
export { securityResearchSkill } from "./security-research"
|
||||||
export { securityReviewSkill } from "./security-review"
|
export { securityReviewSkill } from "./security-review"
|
||||||
export * from "./team-mode"
|
export * from "./team-mode"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -1,206 +1,8 @@
|
|||||||
import type { BuiltinSkill } from "../types"
|
import type { BuiltinSkill } from "../types"
|
||||||
|
import { securityResearchSkill } from "./security-research"
|
||||||
|
|
||||||
export const securityReviewSkill: BuiltinSkill = {
|
export const securityReviewSkill: BuiltinSkill = {
|
||||||
name: "security-review",
|
name: "security-review",
|
||||||
description:
|
description: `Alias for security-research. ${securityResearchSkill.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: securityResearchSkill.template,
|
||||||
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.
|
|
||||||
`,
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user