Building an Automated Security Scanning Pipeline: From Zero to Full OWASP Coverage in CI/CD
Some links in this article may be affiliate links. We may earn a commission if you purchase through them, at no extra cost to you.
Most teams know they should be scanning for security vulnerabilities. Few have a pipeline that actually covers the OWASP Top 10 end-to-end. This guide walks through building an automated security scanning pipeline from scratch — tool selection, scan orchestration, finding triage, and CI/CD integration. No theory. Just the architecture that works.
Pipeline Architecture
An effective security scanning pipeline has four layers, each running at a different point in the development lifecycle:
| Layer | When | What It Catches | Tools |
|---|---|---|---|
| 1. Static Analysis | Every PR | Hardcoded secrets, insecure patterns, code smells | Semgrep, Gitleaks, TruffleHog |
| 2. Dependency Scanning | Every PR + daily | Known CVEs in dependencies | Trivy, npm audit, pip-audit |
| 3. Dynamic Scanning | Post-deploy to staging | Runtime vulnerabilities (XSS, SQLi, SSRF, auth flaws) | ZAP, Nuclei, SecurityClaw |
| 4. Config Auditing | Continuous | TLS misconfig, missing headers, exposed services | SecurityClaw, testssl.sh, Mozilla Observatory |
Each layer catches different vulnerability classes. No single layer covers everything. The pipeline's strength comes from layering — what static analysis misses, dynamic scanning catches. What dynamic scanning misses, configuration auditing catches.
Layer 1: Static Analysis (Pre-Deploy)
Static analysis runs on every pull request before code is merged. It catches issues that are visible in source code without running the application.
What to scan for:
- Hardcoded secrets (API keys, passwords, tokens) — Gitleaks or TruffleHog
- Insecure code patterns (eval(), innerHTML, SQL string concatenation) — Semgrep
- Missing input validation on user-facing endpoints — Semgrep custom rules
- Insecure cryptographic usage (MD5, SHA1 for passwords) — Semgrep
Implementation: Add as a required check on pull requests. The scan should block merge if it finds high-severity issues (hardcoded secrets, SQL injection patterns). Medium-severity issues (missing input validation) should warn but not block.
OWASP coverage: A02 (hardcoded keys), A03 (injection patterns in code), A05 (insecure defaults).
Key principle: Static analysis has the highest false positive rate of any layer. Tune your rules aggressively — a noisy scanner that developers ignore is worse than no scanner at all. Start with 5-10 high-confidence rules and expand gradually.
Layer 2: Dependency Scanning (Pre-Deploy)
Dependency scanning checks your third-party libraries against known vulnerability databases. It runs on every PR (to catch new vulnerable dependencies) and daily (to catch newly disclosed CVEs in existing dependencies).
What to scan:
- npm packages —
npm auditor Trivy - Python packages —
pip-auditor Trivy - Container images — Trivy
- OS packages — Trivy
Implementation: Trivy is the most versatile option — it scans npm, pip, Go modules, container images, and OS packages with a single tool. Run it in CI on every PR and as a daily cron job against your deployed images.
OWASP coverage: A06 (Vulnerable and Outdated Components) — this is the primary layer for A06.
Key principle: Not every CVE is exploitable in your context. A vulnerability in a function you never call is low risk. Prioritize CVEs that affect code paths your application actually uses. Trivy's --ignore-unfixed flag filters out CVEs with no available patch — useful for reducing noise.
Layer 3: Dynamic Scanning (Post-Deploy)
Dynamic scanning tests the running application by sending requests and analyzing responses. This is where you catch runtime vulnerabilities that static analysis can't see — XSS, SQL injection, SSRF, authentication flaws, and access control issues.
Tool selection:
| Tool | Strength | Best For |
|---|---|---|
| OWASP ZAP | Broad coverage, good spider/crawler | General web app scanning, CI/CD baseline |
| Nuclei | Template-based, fast, community templates | Known vulnerability checks, misconfig detection |
| SecurityClaw | Skill-based, OWASP-mapped, campaign orchestration | Targeted OWASP coverage, automated campaigns |
| Burp Suite Pro | Deep scanning, excellent crawler | Manual + automated hybrid testing |
Implementation: Run dynamic scans against your staging environment after every deployment. Use ZAP for broad coverage (spider + active scan), Nuclei for known vulnerability templates, and SecurityClaw for targeted OWASP skill checks. Don't run active injection scans (XSS, SQLi, SSRF) against production without explicit approval.
OWASP coverage: A01 (access control), A03 (injection), A04 (insecure design), A07 (auth failures), A10 (SSRF).
Key principle: Dynamic scanning is slow. A full ZAP active scan can take hours. Run a fast baseline scan (passive + spider) on every deploy, and a full active scan on a weekly schedule. This balances coverage with pipeline speed.
Layer 4: Configuration Auditing (Continuous)
Configuration auditing checks the deployed infrastructure for security misconfigurations — TLS settings, HTTP headers, exposed services, and cloud resource policies. It runs continuously because configurations can change independently of code deployments.
What to audit:
- TLS configuration — protocol versions, cipher suites, certificate validity, HSTS
- HTTP security headers — CSP, X-Frame-Options, X-Content-Type-Options, SameSite cookies
- CORS policy — overly permissive origins, credentials with wildcard
- Exposed services — admin panels, debug endpoints, database interfaces
- Cloud configuration — S3 bucket policies, IAM permissions, security groups
Implementation: Run SecurityClaw's tls-crypto-auditor, security-header-checker, and apigw-cors-tester on a daily cron. Use Mozilla Observatory for a quick external check. For cloud configuration, use AWS Config rules, Azure Policy, or GCP Organization Policy.
OWASP coverage: A02 (TLS), A04 (headers), A05 (misconfiguration).
Key principle: Configuration drift is real. A TLS configuration that was correct last month may be insecure today if a certificate expired or a load balancer was reconfigured. Continuous auditing catches drift that point-in-time scans miss.
Scan Orchestration
Running 4 layers of scanning generates a lot of data. Orchestration is how you manage it without drowning in findings.
Scan scheduling:
- Layer 1 (static) — every PR, blocking merge on high severity
- Layer 2 (dependencies) — every PR + daily cron
- Layer 3 (dynamic baseline) — every staging deploy
- Layer 3 (dynamic full) — weekly scheduled
- Layer 4 (config audit) — daily cron
Result aggregation: All scan results should flow into a single dashboard or issue tracker. Don't make developers check 4 different tools for findings. Options: DefectDojo (open source), GitHub Security tab (if using GitHub Advanced Security), or a custom aggregation script that creates issues from scan output.
Deduplication: Multiple tools will find the same issue. A missing CSP header will be flagged by ZAP, SecurityClaw, and Mozilla Observatory. Deduplicate by (URL + finding type + severity) before creating issues.
Finding Triage: Separating Signal from Noise
The hardest part of security scanning isn't running the scans — it's triaging the results. A typical first scan of a web application produces hundreds of findings. Most are low severity, many are false positives, and a few are critical.
Triage priority:
| Priority | Finding Type | Action | SLA |
|---|---|---|---|
| P0 — Critical | Hardcoded secrets, SQLi, RCE, SSRF to cloud metadata | Fix immediately, rotate credentials | 24 hours |
| P1 — High | XSS, IDOR, auth bypass, missing TLS | Fix in current sprint | 1 week |
| P2 — Medium | Missing headers, weak TLS ciphers, CORS misconfig | Schedule fix | 1 month |
| P3 — Low | Information disclosure, missing SRI, verbose errors | Track, fix when convenient | Quarterly |
False positive management: Every scanner produces false positives. The key is to have a documented process for marking findings as false positives so they don't reappear in future scans. Most tools support suppression files or baseline configurations. Maintain these as code alongside your application.
CI/CD Integration Patterns
There are three patterns for integrating security scanning into CI/CD:
Pattern 1: Gate (blocking) — The scan runs as a required check. If it finds issues above a severity threshold, the pipeline fails and the deployment is blocked. Best for: Layer 1 (secrets) and Layer 2 (critical CVEs).
Pattern 2: Report (non-blocking) — The scan runs and posts results as a comment or dashboard update, but doesn't block the pipeline. Best for: Layer 3 (dynamic scanning) and Layer 4 (config auditing), where false positives are common and blocking would slow development.
Pattern 3: Async (scheduled) — The scan runs on a schedule (daily, weekly) independent of deployments. Results are aggregated and triaged separately. Best for: Full active scans (Layer 3) and continuous monitoring (Layer 4).
Most teams use a combination: Gate for secrets and critical CVEs, Report for dynamic baseline scans, and Async for full active scans.
OWASP Coverage Map
Here's how the four layers map to the OWASP Top 10:
| OWASP | L1 Static | L2 Deps | L3 Dynamic | L4 Config |
|---|---|---|---|---|
| A01 Broken Access Control | — | — | ✅ | — |
| A02 Cryptographic Failures | ✅ | — | — | ✅ |
| A03 Injection | ✅ | — | ✅ | — |
| A04 Insecure Design | — | — | ✅ | ✅ |
| A05 Security Misconfiguration | ✅ | — | ✅ | ✅ |
| A06 Vulnerable Components | — | ✅ | ✅ | — |
| A07 Auth Failures | — | — | ✅ | — |
| A08 Data Integrity | ✅ | ✅ | ✅ | — |
| A09 Logging/Monitoring | — | — | ✅ | — |
| A10 SSRF | ✅ | — | ✅ | — |
Every OWASP category is covered by at least one layer. Most are covered by two or three. This redundancy is intentional — different layers catch different manifestations of the same vulnerability class.
Common Mistakes
1. Scanning production with active injection tests. XSS probes, SQL injection payloads, and SSRF attempts can break production applications. Always run active scans against staging or a dedicated security testing environment.
2. Blocking CI/CD on every finding. If your pipeline fails on every medium-severity finding, developers will either disable the scanner or stop caring about the results. Block only on critical and high severity. Report everything else.
3. Running scans without triaging results. A scan that produces 500 findings and no one looks at them is worse than no scan — it creates a false sense of security. Assign ownership for triage. If no one is triaging, reduce scan scope until someone is.
4. Scanning only at deploy time. New CVEs are disclosed daily. A dependency that was safe yesterday may have a critical CVE today. Run dependency scans on a daily schedule, not just at deploy time.
5. Not maintaining false positive suppressions. Every scanner produces false positives. If you don't maintain a suppression file, the same false positives will appear in every scan, burying real findings in noise. Treat suppression files as code — review them, version them, and audit them periodically.
Bottom Line
A security scanning pipeline isn't a single tool — it's four layers working together. Static analysis catches code-level issues before merge. Dependency scanning catches known CVEs in libraries. Dynamic scanning catches runtime vulnerabilities in the running application. Configuration auditing catches infrastructure misconfigurations continuously.
Start with Layer 1 (secrets scanning) and Layer 2 (dependency scanning) — they're the easiest to implement and have the lowest false positive rate. Add Layer 3 (dynamic scanning) once you have a staging environment. Add Layer 4 (config auditing) once you're deploying to production.
The goal isn't zero findings — it's a process that catches critical issues before they reach production and gives your team a clear path to fix everything else. Build the pipeline, triage the results, and iterate.