Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Integrates Static Application Security Testing (SAST), Dynamic Application Security Testing (DAST), and Software Composition Analysis (SCA) into CI/CD pipelines using open-source tools. Covers Semgrep for SAST, Trivy for SCA and container scanning, OWASP ZAP for DAST, and Gitleaks for secrets detection. Activates for requests involving DevSecOps pipeline setup, automated security scanning in CI/CD, SAST/DAST/SCA integration, or shift-left security implementation.
.claude/skills/implementing-devsecops-security-scanning/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flashlowest | 97% | 113 |
| gemini-3.1-pro-preview | 100% | 1 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-20 | ✗→✓ | ▲ Improved | — | — |
| case-21 | ✗→✓ | ▲ Improved | — | — |
| case-11 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-03 | ✗→✓ | ▲ Improved | — | — |
Do not use as a replacement for manual penetration testing. Automated scanning catches common vulnerability patterns but cannot replace human-driven security assessments for business logic flaws and complex attack chains.
p/security-audit, p/owasp-top-ten)Secrets detection runs first because leaked credentials are the highest-priority finding. Add to .github/workflows/security.yml:
yamlname: DevSecOps Security Pipeline on: push: branches: [main, develop] pull_request: branches: [main] jobs: secrets-scan: name: Secrets Detection (Gitleaks) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for scanning all commits - name: Run Gitleaks uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Configure .gitleaks.toml in the repository root for custom rules and allowlists:
toml[extend] useDefault = true [allowlist] description = "Global allowlist" paths = [ '''\.gitleaks\.toml''', '''test/fixtures/.*''', '''docs/examples/.*''' ] [[rules]] id = "custom-internal-api-key" description = "Internal API key pattern" regex = '''INTERNAL_KEY_[A-Za-z0-9]{32}''' tags = ["internal", "api-key"]
Semgrep performs static code analysis to find security vulnerabilities, bugs, and code patterns:
yamlsast-scan: name: SAST (Semgrep) runs-on: ubuntu-latest container: image: semgrep/semgrep steps: - uses: actions/checkout@v4 - name: Run Semgrep SAST scan run: | semgrep scan \ --config p/security-audit \ --config p/owasp-top-ten \ --config p/secrets \ --severity ERROR \ --error \ --json \ --output semgrep-results.json \ . - name: Upload SAST results if: always() uses: actions/upload-artifact@v4 with: name: semgrep-results path: semgrep-results.json
For custom rules, create .semgrep/custom-rules.yml:
yamlrules: - id: no-exec-user-input patterns: - pattern: exec($INPUT) - pattern-not: exec("...") message: > User input passed to exec(). This is a command injection vulnerability. severity: ERROR languages: [python] metadata: cwe: "CWE-78: OS Command Injection" owasp: "A03:2021 - Injection" - id: no-raw-sql-queries patterns: - pattern: cursor.execute(f"...") - pattern: cursor.execute("..." + ...) message: > SQL query built with string concatenation or f-strings. Use parameterized queries. severity: ERROR languages: [python] metadata: cwe: "CWE-89: SQL Injection" owasp: "A03:2021 - Injection"
Trivy scans dependencies, container images, IaC files, and generates SBOM:
yamlsca-scan: name: SCA & Container Scan (Trivy) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Trivy filesystem scan (dependencies) uses: aquasecurity/trivy-action@0.28.0 with: scan-type: 'fs' scan-ref: '.' severity: 'CRITICAL,HIGH' exit-code: '1' format: 'json' output: 'trivy-fs-results.json' - name: Run Trivy IaC scan (Terraform, CloudFormation) uses: aquasecurity/trivy-action@0.28.0 with: scan-type: 'config' scan-ref: '.' severity: 'CRITICAL,HIGH' exit-code: '1' format: 'json' output: 'trivy-iac-results.json' - name: Upload SCA results if: always() uses: actions/upload-artifact@v4 with: name: trivy-results path: trivy-*.json container-scan: name: Container Image Scan (Trivy) runs-on: ubuntu-latest needs: [sast-scan] # Build image only after SAST passes steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t app:${{ github.sha }} . - name: Scan container image uses: aquasecurity/trivy-action@0.28.0 with: image-ref: 'app:${{ github.sha }}' severity: 'CRITICAL,HIGH' exit-code: '1' format: 'json' output: 'trivy-image-results.json' - name: Generate SBOM uses: aquasecurity/trivy-action@0.28.0 with: image-ref: 'app:${{ github.sha }}' format: 'cyclonedx' output: 'sbom.json' - name: Upload SBOM uses: actions/upload-artifact@v4 with: name: sbom path: sbom.json
DAST runs against a deployed staging environment. It is slower than SAST/SCA and should run asynchronously or on a schedule:
yamldast-scan: name: DAST (OWASP ZAP) runs-on: ubuntu-latest needs: [deploy-staging] # Must run after app is deployed to staging steps: - uses: actions/checkout@v4 - name: Run ZAP Baseline Scan (fast, suitable for CI) uses: zaproxy/action-baseline@v0.14.0 with: target: ${{ vars.STAGING_URL }} rules_file_name: '.zap/rules.tsv' cmd_options: '-a -j' # For nightly full scans, use action-full-scan instead: # - name: Run ZAP Full Scan (comprehensive, 30-60 min) # uses: zaproxy/action-full-scan@v0.12.0 # with: # target: ${{ vars.STAGING_URL }}
Create .zap/rules.tsv to configure alert thresholds:
tsv10010 IGNORE (Cookie No HttpOnly Flag - acceptable for non-sensitive cookies) 10011 IGNORE (Cookie Without Secure Flag - staging uses HTTP) 90033 WARN (Loosely Scoped Cookie) 10038 FAIL (Content Security Policy Header Not Set) 40012 FAIL (Cross Site Scripting - Reflected) 40014 FAIL (Cross Site Scripting - Persistent) 40018 FAIL (SQL Injection) 90019 FAIL (Server Side Code Injection) 90020 FAIL (Remote OS Command Injection)
Create a summary job that aggregates all scan results and enforces pass/fail gates:
yamlsecurity-gate: name: Security Gate runs-on: ubuntu-latest needs: [secrets-scan, sast-scan, sca-scan, container-scan] if: always() steps: - name: Check scan results run: | echo "Checking security scan results..." # Fail the pipeline if any upstream job failed if [[ "${{ needs.secrets-scan.result }}" == "failure" ]]; then echo "BLOCKED: Secrets detected in repository" exit 1 fi if [[ "${{ needs.sast-scan.result }}" == "failure" ]]; then echo "BLOCKED: SAST found critical/high vulnerabilities" exit 1 fi if [[ "${{ needs.sca-scan.result }}" == "failure" ]]; then echo "BLOCKED: SCA found critical/high vulnerable dependencies" exit 1 fi if [[ "${{ needs.container-scan.result }}" == "failure" ]]; then echo "BLOCKED: Container image has critical/high vulnerabilities" exit 1 fi echo "All security gates passed"
Enforce the security pipeline as a required status check:
GitHub Repository > Settings > Branches > Branch Protection Rules
Branch name pattern: main
Require status checks to pass before merging: Enabled
Required status checks:
- Secrets Detection (Gitleaks)
- SAST (Semgrep)
- SCA & Container Scan (Trivy)
- Security Gate
Require branches to be up to date before merging: EnabledConfigure pre-commit hooks so developers catch issues before pushing:
yaml# .pre-commit-config.yaml repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.22.1 hooks: - id: gitleaks - repo: https://github.com/semgrep/semgrep rev: v1.102.0 hooks: - id: semgrep args: ['--config', 'p/security-audit', '--config', 'p/owasp-top-ten', '--error']
Install and activate pre-commit:
bashpip install pre-commit pre-commit install pre-commit run --all-files # Test against existing codebase
| Term | Definition | |------|------------| | SAST (Static Application Security Testing) | Analyzes source code without executing it to find security vulnerabilities; runs fast, catches issues early, but cannot find runtime flaws | | DAST (Dynamic Application Security Testing) | Tests a running application by sending requests and analyzing responses; finds runtime issues but requires a deployed environment | | SCA (Software Composition Analysis) | Scans project dependencies against vulnerability databases (NVD, GitHub Advisory) to find known-vulnerable libraries | | SBOM (Software Bill of Materials) | Machine-readable inventory of all components and dependencies in an application, used for vulnerability tracking and compliance | | Shift Left | Security practice of moving security testing earlier in the SDLC, from post-deployment to pre-commit and CI stages | | Security Gate | A CI/CD pipeline checkpoint that blocks deployment if security scan results exceed defined severity thresholds | | Pre-commit Hook | Local Git hook that runs security checks before code is committed, providing the fastest developer feedback loop |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.