Commit cb1fd05
feat(security): add basic security reviewer agent with owasp skills (#1008)
This PR introduces a new Security Reviewer agent containing skills
relating to the follow OWASP related content:
- [OWASP Top 10 for Agentic Applications for
2026](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/)
- [OWASP Top 10 for LLM Applications
2025](https://genai.owasp.org/resource/owasp-top-10-for-llm-applications-2025/)
- [OWASP Top 10:2025](https://owasp.org/Top10/2025/)
The agent contains 3 modes to fit a rang of different usecases and they
are:
Mode | Description | Scenario
--- | --- | ---
`audit` | Full audit of target code base for common vulnerabilities |
For use on existing code base. Will take time to complete if repository
is large
`diff` | Only analyse changes on current branch | For use during
validation stage after code base has been modified. Could also be used
within a PR
`plan` | Must provide an implementation plan. Analyse implementation
plan to highlight potental vulnerabilities to look out for with
mitigation suggestions | For use at planning stage to guide the agent
before the implementation stage to mitigate the risk of vulnerabilities
from entering code base
There are also two additional inputs you can pass:
- `targetSkill`: Run a particular skill - skips codebase profiling step
- `scope`: Restricts agent to a particular directory/file
Detail agent flow:
```mermaid
flowchart TD
Start([User Invokes Security Reviewer]) --> SetDate["Pre-req: Set report date"]
SetDate --> DetectMode{"Detect scanning mode"}
DetectMode -->|"explicit or keywords:<br/>changes, branch, PR"| DiffMode["Mode = diff"]
DetectMode -->|"explicit or keywords:<br/>plan, design, RFC"| PlanMode["Mode = plan"]
DetectMode -->|"default / explicit"| AuditMode["Mode = audit"]
DetectMode -->|"invalid mode"| InvalidStop([Stop: Invalid mode])
%% Step 0: Mode-specific setup
AuditMode --> StatusSetup["Status: Starting in audit mode"]
DiffMode --> GitDetect["Detect default branch<br/>git symbolic-ref"]
PlanMode --> ResolvePlan["Resolve plan document<br/>from input / context / fallback"]
GitDetect -->|"fail"| FallbackAudit["Fallback to audit mode"]
FallbackAudit --> StatusSetup
GitDetect -->|"ok"| MergeBase["Compute merge base<br/>git merge-base"]
MergeBase -->|"fail"| FallbackAudit
MergeBase -->|"ok"| ChangedFiles["Get changed files<br/>git diff --name-only"]
ChangedFiles -->|"fail"| FallbackAudit
ChangedFiles -->|"no files"| EmptyStop([Stop: No changed files])
ChangedFiles -->|"files found"| FilterFiles["Filter non-assessable<br/>.md .yml .json images etc."]
FilterFiles -->|"empty after filter"| FilterStop([Stop: No assessable code files])
FilterFiles -->|"assessable files"| StatusSetup
ResolvePlan -->|"no plan found"| AskUser["Ask user for plan path"]
AskUser --> ResolvePlan
ResolvePlan -->|"plan resolved"| ReadPlan["Read plan document"] --> StatusSetup
%% Step 1: Profile Codebase
StatusSetup --> TargetSkill{"targetSkill<br/>provided?"}
TargetSkill -->|"yes"| ValidateSkill{"Skill in<br/>Available Skills?"}
ValidateSkill -->|"no"| SkillStop([Stop: Show available skills])
ValidateSkill -->|"yes"| StubProfile["Build minimal profile stub<br/>skip Codebase Profiler"]
StubProfile --> SetSkills1["Applicable skills = targetSkill only"]
TargetSkill -->|"no"| RunProfiler[/"Subagent: Codebase Profiler<br/>mode-specific prompt"/]
RunProfiler -->|"fail"| ProfileFail([Stop: Profiling failed])
RunProfiler -->|"ok"| IntersectSkills["Intersect profiler skills<br/>with Available Skills"]
IntersectSkills --> SpecificOverride{"Specific skills<br/>list provided?"}
SpecificOverride -->|"yes"| OverrideSkills["Override with provided list<br/>intersect with Available Skills"]
SpecificOverride -->|"no"| CheckEmpty{"Any applicable<br/>skills?"}
OverrideSkills --> CheckEmpty
CheckEmpty -->|"none"| NoSkillStop([Stop: No applicable skills])
CheckEmpty -->|"skills found"| SetSkills2["Set applicable skills list"]
SetSkills1 --> StatusProfile["Status: Profiling complete"]
SetSkills2 --> StatusProfile
%% Step 2: Assess Skills
StatusProfile --> AssessLoop["Status: Beginning skill assessments"]
AssessLoop --> ForEachSkill["For each applicable skill<br/>(parallel when supported)"]
ForEachSkill --> RunAssessor[/"Subagent: Skill Assessor<br/>mode-specific prompt per skill"/]
RunAssessor -->|"incomplete"| RetryAssessor[/"Retry Skill Assessor<br/>(once)"/]
RetryAssessor -->|"still fails"| ExcludeSkill["Exclude skill from results"]
RetryAssessor -->|"ok"| CollectFindings["Collect structured findings"]
RunAssessor -->|"ok"| CollectFindings
ExcludeSkill --> AllDone{"All skills<br/>processed?"}
CollectFindings --> AllDone
AllDone -->|"no"| ForEachSkill
AllDone -->|"yes"| CheckAllFailed{"All assessments<br/>failed?"}
CheckAllFailed -->|"yes"| AllFailStop([Stop: All assessments failed])
CheckAllFailed -->|"no"| StatusAssess["Status: All assessments complete"]
%% Step 3: Verify Findings
StatusAssess --> IsPlanMode{"Mode = plan?"}
IsPlanMode -->|"yes"| SkipVerify["Skip verification<br/>pass findings through unchanged"]
IsPlanMode -->|"no"| VerifyLoop["Status: Adversarial verification"]
VerifyLoop --> ForEachSkillV["For each skill's findings<br/>(parallel when supported)"]
ForEachSkillV --> Classify["Classify findings"]
Classify --> PassThrough["PASS + NOT_ASSESSED<br/>verdict = UNCHANGED"]
Classify --> Serialize["FAIL + PARTIAL<br/>serialize findings"]
Serialize --> HasUnverified{"Any FAIL/PARTIAL<br/>findings?"}
HasUnverified -->|"no"| MergeVerified["Merge into verified collection"]
HasUnverified -->|"yes"| RunVerifier[/"Subagent: Finding Deep Verifier<br/>all FAIL+PARTIAL in single call"/]
RunVerifier -->|"incomplete"| RetryVerifier[/"Retry Verifier (once)"/]
RetryVerifier --> CaptureVerdicts["Capture deep verdicts"]
RunVerifier -->|"ok"| CaptureVerdicts
PassThrough --> MergeVerified
CaptureVerdicts --> MergeVerified
MergeVerified --> AllVerified{"All skills<br/>verified?"}
AllVerified -->|"no"| ForEachSkillV
AllVerified -->|"yes"| StatusVerify["Status: All findings verified"]
SkipVerify --> StatusVerify
%% Step 4: Generate Report
StatusVerify --> RunReporter[/"Subagent: Report Generator<br/>mode-specific prompt + verified findings"/]
RunReporter --> CaptureReport["Capture report path +<br/>summary counts + severity"]
%% Step 5: Completion
CaptureReport --> StatusReport["Status: Report generation complete"]
StatusReport --> IsPlanReport{"Mode = plan?"}
IsPlanReport -->|"yes"| PlanCompletion["Display plan completion format<br/>risk counts + report path"]
IsPlanReport -->|"no"| AuditCompletion["Display audit/diff completion format<br/>severity + verification + finding counts"]
PlanCompletion --> ExcludedNote{"Excluded skills?"}
AuditCompletion --> ExcludedNote
ExcludedNote -->|"yes"| AppendNote["Append excluded skills note"]
ExcludedNote -->|"no"| Done([Scan Complete])
AppendNote --> Done
%% Styling
classDef subagent fill:#4a90d9,color:#fff,stroke:#2c5f8a
classDef stop fill:#e74c3c,color:#fff,stroke:#c0392b
classDef decision fill:#f5c542,color:#333,stroke:#d4a017
classDef status fill:#2ecc71,color:#fff,stroke:#27ae60
class RunProfiler,RunAssessor,RetryAssessor,RunVerifier,RetryVerifier,RunReporter subagent
class InvalidStop,EmptyStop,FilterStop,ProfileFail,SkillStop,NoSkillStop,AllFailStop stop
class DetectMode,TargetSkill,ValidateSkill,SpecificOverride,CheckEmpty,AllDone,CheckAllFailed,IsPlanMode,HasUnverified,AllVerified,IsPlanReport,ExcludedNote decision
class StatusSetup,StatusProfile,StatusAssess,StatusVerify,StatusReport status
```
## Related Issue(s)
- Closes #794
- Closes #793
- Closes #796
- Closes #795
## Type of Change
Select all that apply:
**Code & Documentation:**
* [x] Bug fix (non-breaking change fixing an issue)
* [x] New feature (non-breaking change adding functionality)
* [ ] Breaking change (fix or feature causing existing functionality to
change)
* [ ] Documentation update
**Infrastructure & Configuration:**
* [ ] GitHub Actions workflow
* [ ] Linting configuration (markdown, PowerShell, etc.)
* [ ] Security configuration
* [ ] DevContainer configuration
* [ ] Dependency update
**AI Artifacts:**
* [x] Reviewed contribution with `prompt-builder` agent and addressed
all feedback
* [x] Copilot instructions (`.github/instructions/*.instructions.md`)
* [ ] Copilot prompt (`.github/prompts/*.prompt.md`)
* [x] Copilot agent (`.github/agents/*.agent.md`)
* [x] Copilot skill (`.github/skills/*/SKILL.md`)
> Note for AI Artifact Contributors:
>
> * Agents: Research, indexing/referencing other project (using standard
VS Code GitHub Copilot/MCP tools), planning, and general implementation
agents likely already exist. Review `.github/agents/` before creating
new ones.
> * Skills: Must include both bash and PowerShell scripts. See
[Skills](../docs/contributing/skills.md).
> * Model Versions: Only contributions targeting the **latest Anthropic
and OpenAI models** will be accepted. Older model versions (e.g.,
GPT-3.5, Claude 3) will be rejected.
> * See [Agents Not
Accepted](../docs/contributing/custom-agents.md#agents-not-accepted) and
[Model Version
Requirements](../docs/contributing/ai-artifacts-common.md#model-version-requirements).
**Other:**
* [ ] Script/automation (`.ps1`, `.sh`, `.py`)
* [ ] Other (please describe):
## Sample Prompts (for AI Artifact Contributions)
<!-- If you checked any boxes under "AI Artifacts" above, provide a
sample prompt showing how to use your contribution -->
<!-- Delete this section if not applicable -->
**User Request:**
<!-- What natural language request would trigger this
agent/prompt/instruction? -->
> Analyse the code base and reproduce a detailed security report
containing common vulnerabilities
**Execution Flow:**
<!-- Step-by-step: what happens when invoked? Include tool usage,
decision points -->
1. The user switches to the `Security Reviewer` agent with prompt
`Analyse the code base and reproduce a detailed security report`. By
default the agent will run in `audit`mode. This will do a full audit of
the current codebase.
2. The Security Reviewer agent will then proceed with the following
execution steps via subagents: Analyse codebase and select relevant
owasp skills via `Codebase Profiler` agent -> Create subagents for each
identified owasp skill to analyse codebase against owasp skill's
knowledge base via `Skill Assessor` agent -> New subagents are created
for each owasp skill to verify and challenge the agent's findings via
`Finding Deep Verifier` agent -> Collate results and generate a report
via `Report Generator` agent
3. Report contains the results of the assessment, including links to
offending files with details explanation of the findings, and
remediation suggestions
**Output Artifacts:**
<!-- What files/content are created? Show first 10-20 lines as preview
-->
- `audit` mode:
`.copilot-tracking/security/{date}/security-report-001.md`
- `diff` mode:
`.copilot-tracking/security/{date}/security-report-diff-001.md`
- `plan` mode:
`.copilot-tracking/security/{date}/plan-risk-assessment-001.md`
**Success Indicators:**
<!-- How does user know it worked correctly? What validation should they
perform? -->
- A details report is generated and saved under
`.copilot-tracking/security/{date}/`
- Report should contain the following:
- Summary count
- Serverity breakdown
- Verification summary
- Findings by framework
- Detailed remediation guidance
- Disproved findings
## Testing
<!-- Describe how you tested these changes -->
Check | Command | Status
-- | -- | --
Markdown linting | npm run lint:md | ✅ Pass
Spell checking | npm run spell-check | ✅ Pass
Frontmatter validation | npm run lint:frontmatter | ✅ Pass
Skill structure validation | npm run validate:skills | ✅ Pass
Link validation | npm run lint:md-links | ✅ Pass
PowerShell analysis | npm run lint:ps | ✅ Pass
Plugin freshness | npm run plugin:generate | ✅ Pass
I had to modify `CollectionHelpers.psm1` for `npm run plugin:generate`
to work. My owasp skills contained a handful of `.md` used for
reference. `CollectionHelpers.psm1` would automatically add these `.md`s
to the `hev-core-all.collection.yaml` with `kind: "0"`. `kind: "0"` is
not a recongised `kind` and would cause an error and updating `kind` to
`skill` would just get overridden when you run `npm run plugin:generate`
again. To resolve this I updated the script to ignore `.md` under the
`skills` folder
## Checklist
### Required Checks
* [ ] Documentation is updated (if applicable)
* [x] Files follow existing naming conventions
* [ ] Changes are backwards compatible (if applicable)
* [ ] Tests added for new functionality (if applicable)
### AI Artifact Contributions
<!-- If contributing an agent, prompt, instruction, or skill, complete
these checks -->
* [x] Used `/prompt-analyze` to review contribution
* [x] Addressed all feedback from `prompt-builder` review
* [x] Verified contribution follows common standards and type-specific
requirements
### Required Automated Checks
The following validation commands must pass before merging:
* [x] Markdown linting: `npm run lint:md`
* [x] Spell checking: `npm run spell-check`
* [x] Frontmatter validation: `npm run lint:frontmatter`
* [x] Skill structure validation: `npm run validate:skills`
* [x] Link validation: `npm run lint:md-links`
* [x] PowerShell analysis: `npm run lint:ps`
* [x] Plugin freshness: `npm run plugin:generate`
## Security Considerations
<!-- 1 parent 27fbd33 commit cb1fd05
File tree
80 files changed
+6054
-326
lines changed- .github
- agents/security
- subagents
- skills
- experimental
- powerpoint
- video-to-gif
- vscode-playwright
- installer/hve-core-installer
- security
- owasp-agentic
- references
- owasp-llm
- references
- owasp-top-10
- references
- security-reviewer-formats
- references
- .vscode
- collections
- plugins
- hve-core-all
- agents
- skills
- security
- agents
- skills
- scripts/linting/schemas
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
80 files changed
+6054
-326
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
| 72 | + | |
72 | 73 | | |
73 | 74 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
75 | 76 | | |
76 | 77 | | |
77 | 78 | | |
| |||
295 | 296 | | |
296 | 297 | | |
297 | 298 | | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
298 | 319 | | |
299 | 320 | | |
300 | 321 | | |
| |||
Large diffs are not rendered by default.
Lines changed: 166 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
0 commit comments