A GitHub Actions workflow that automatically reviews pull request diffs for security vulnerabilities using GitHub Copilot. in this example Copilot but if course can be used with any AI agent and model. Every time someone opens or updates a PR, the workflow diffs the changes, feeds them into Copilot with a detailed security audit prompt, and posts the results as a PR comment, updating the comment as the open CVEs are resolved.
A security-focused code review that runs on every PR without any manual effort.
When a PR is opened or updated, the workflow:
- Diffs the PR against the base branch
- Passes the diff to Github Copilot with a security-focused prompt (OWASP Top 10, secrets detection, dependency checks, etc.)
- Parses Copilot's response and extracts structured findings with severity levels (
CRITICAL,HIGH,MEDIUM,LOW) and CVSS-style risk scores - Posts or updates a comment on the PR with a summary table of findings
- Optionally blocks the PR from merging if CRITICAL findings are present or the max CVSS score exceeds a configurable threshold
- A GitHub fine-grained PAT with Copilot Requests permission, stored as a repository secret named
COPILOT_PAT
- GitHub Actions enabled on your repo
- Copy
.github/workflows/security-audit.yml,.github/prompts/security-audit-owasp.prompt.txt, and.github/prompts/security-audit-stride.prompt.txtinto your repository - Add your
COPILOT_PATsecret under Settings → Secrets and variables → Actions - The workflow triggers automatically on pull requests and subsequent pushes to that PR
Note: There is now a second security scanning prompt available: security-audit-stride.prompt.txt. The default remains OWASP if no override is used.
At the top of the workflow file there are a few env vars you can tweak:
| Variable | Default | Description |
|---|---|---|
CVSS_BLOCK_THRESHOLD |
9.0 |
CVSS score at or above this value will block the PR |
ENABLE_COPILOT_AUDIT |
true |
Set to false to skip the Copilot audit step |
SKIP_PROMPT_INJECTION_FINDINGS |
true |
Ignores findings that are about the audit prompt itself |
SKIP_SELF_AUDIT_FINDINGS |
true |
Ignores findings flagging the workflow file itself |
DIFF_IGNORE_GLOBS |
*.spec.ts,*.spec.tsx,*.md,*.mdx |
Comma-separated git path globs excluded from diff context sent to the model |
DIFF_MAX_BYTES |
200000 |
Max diff payload size before truncation and a blocking coverage warning |
The workflow runs one security audit prompt per invocation. Supported profiles:
owasp(default) → uses.github/prompts/security-audit-owasp.prompt.txtstride→ uses.github/prompts/security-audit-stride.prompt.txt
To audit using a specific prompt, provide the audit_prompt input when calling the workflow via workflow_call. If you want to run both OWASP and STRIDE audits on the same PR, invoke the workflow twice with different audit_prompt values. Each run has its own concurrency group, so they won't cancel each other.
Note:
.github/workflows/security-audit.ymlalso has a directpull_requesttrigger. If you call it from a separate caller workflow that also triggers onpull_request, the audit will run twice - once from the caller and once directly. To avoid duplicate runs, either remove thepull_requesttrigger fromsecurity-audit.yml(making itworkflow_call-only) or ensure only one workflow handles the trigger.
Example: Call security-audit once with STRIDE prompt
name: Run Security Audit
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
audit-stride:
uses: ./.github/workflows/security-audit.yml
with:
audit_prompt: stride
secrets: inheritExample: Run both OWASP and STRIDE audits (two separate jobs)
name: Run Security Audits (Multiple)
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
audit-owasp:
uses: ./.github/workflows/security-audit.yml
with:
audit_prompt: owasp
secrets: inherit
audit-stride:
uses: ./.github/workflows/security-audit.yml
with:
audit_prompt: stride
secrets: inheritEach job runs independently and produces its own PR comment, clearly labeled with the prompt profile used.
If a PR gets blocked and you've reviewed the findings manually, two labels can be applied by an authorized approver to allow the merge to proceed:
security-override-critical- overrides the CRITICAL finding blocksecurity-override-cvss- overrides the CVSS threshold block
The approver must be listed in SECURITY_OVERRIDE_APPROVERS (defaults to the repo owner), and the PR author cannot override their own PR.
- The PR diff is capped at ~120KB before being sent to Copilot. If truncated, the workflow will warn and block the PR pending a manual review.
- The audit prompts are in
.github/prompts/security-audit-owasp.prompt.txtand.github/prompts/security-audit-stride.prompt.txt. This is intentionally opinionated about security. It will flag things aggressively including itself. Use the skip/override controls to tune it for your needs.
