Add a .github/workflows/security.yml file with three steps: checkout, install Custodia CLI, run scan. Use --fail-on critical to block the PR on critical findings. The workflow covers OWASP Top 10, OWASP LLM Top 10, EU AI Act, and NIST AI RMF in a single pass — no additional tools required. Scan results are uploaded as a workflow artifact and linked in a PR comment automatically.
Fixing a vulnerability in production costs 30× more than fixing it at commit time — in engineering hours, incident response, and potential breach costs. The CI pipeline is the last automated gate before code reaches customers. Every critical OWASP finding that passes through is a breach waiting to happen.
For AI-powered applications, the case is stronger: OWASP LLM Top 10 vulnerabilities like prompt injection and excessive agency are invisible to traditional CI tools. Without a dedicated AI security scan in your pipeline, LLM-specific vulnerabilities have no automated detection gate.
Most teams end up running 3–4 security tools in CI to get reasonable coverage. Custodia is the first single-tool option that covers traditional web security, AI security, and compliance frameworks.
| Tool | OWASP Top 10 | OWASP LLM | EU AI Act | Dependencies | PR Comments | Block Mode |
|---|---|---|---|---|---|---|
| Custodia | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Snyk Action | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ |
| CodeQL | ✓ | ✗ | ✗ | ✗ | ✓ | ✓ |
| OWASP ZAP | ✓ | ✗ | ✗ | ✗ | ✗ | ✓ |
| Semgrep CI | ✓ | ✗ | ✗ | ✗ | ✓ | ✓ |
| Trivy | ✗ | ✗ | ✗ | ✓ | ✗ | ✓ |
Settings → Secrets and variables → Actions → New repository secret. Name: CUSTODIA_API_KEY
The easiest way is the Custodia Security Scan action on the GitHub Marketplace — two steps, no manual CLI install needed:
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
security:
name: OWASP + AI Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: contactdavidpersonal-code/custodia-scan-action@v1
with:
api-key: ${{ secrets.CUSTODIA_API_KEY }} # Add this step after the scan step:
- name: Comment findings on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('report.json', 'utf8'));
const { score, findings } = report;
const critical = findings.filter(f => f.severity === 'CRITICAL');
const high = findings.filter(f => f.severity === 'HIGH');
const body = [
'## 🔐 Custodia Security Scan',
`**Score:** ${score}/100`,
`**Critical:** ${critical.length} **High:** ${high.length}`,
'',
critical.length > 0
? '⛔ **Deploy blocked** — critical findings must be resolved.'
: '✅ No critical findings. Review high severity before merge.',
'',
`[View full report](https://custodia.dev/reports/${report.reportId})`,
].join('\n');
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
}); # Only scan files changed in this PR
- name: Get changed files
id: changed
run: |
echo "files=$(git diff --name-only origin/main HEAD | grep -E '^src/' | tr '\n' ' ')" >> $GITHUB_OUTPUT
- name: Run incremental scan
if: steps.changed.outputs.files != ''
run: custodia scan ${{ steps.changed.outputs.files }} --fail-on critical
env:
CUSTODIA_API_KEY: ${{ secrets.CUSTODIA_API_KEY }}Overly aggressive blocking causes security fatigue — developers start bypassing checks. Overly lenient blocking means critical vulnerabilities flow to production. The right policy:
CRITICALHIGHMEDIUMLOW/INFO# Custodia --fail-on flag maps exactly to this policy: custodia scan . --fail-on critical # block on CRITICAL only custodia scan . --fail-on high # block on HIGH+ custodia scan . --fail-on medium # block on MEDIUM+ (strict) custodia scan . # never block, always report
Add a .github/workflows/security.yml file. Install Custodia CLI, run custodia scan . --fail-on critical, and the workflow blocks the PR if any critical vulnerabilities are found. Full YAML template is in this guide.
CodeQL performs deep semantic analysis but requires per-language configuration and does not cover OWASP LLM Top 10. Snyk focuses on dependency vulnerabilities and some SAST. Custodia covers OWASP Top 10, OWASP LLM Top 10, EU AI Act, and NIST AI RMF in one pass — no additional tools required for teams shipping AI features.
Block on critical and high severity. Warn on medium. Never block on informational findings. Overly aggressive gates cause security fatigue and get bypassed. The right policy: fail CI on CRITICAL, post PR comments for HIGH/MEDIUM, and upload full report as an artifact for all findings.
Add it as a GitHub repository secret: Settings → Secrets and variables → Actions → New repository secret. Name: CUSTODIA_API_KEY. Reference in workflow as ${{ secrets.CUSTODIA_API_KEY }}. Never hardcode keys in YAML files — they are stored in version control.
Under 90 seconds for most codebases under 100k lines. Custodia uses SHA-256 codebase caching — unchanged files are skipped on subsequent scans. Large monorepos can use git diff to scope scans to changed directories and reduce CI scan time to under 30 seconds.
Free tier includes CI scanning. Pro plan ($39/mo) unlocks OWASP LLM Top 10, AI fix prompts, and compliance reports.