Modern software delivery pipelines can deploy code dozens or even hundreds of times per day. Traditional penetration testing models, where security teams perform assessments quarterly or before major releases, simply cannot keep pace.
Attackers do not wait for the next security review.
Every pull request, dependency update, infrastructure change, or container image introduces potential risk. Integrating penetration testing into CI/CD enables organizations to identify vulnerabilities before they reach production.
The goal is not replacing human penetration testers. The goal is automating everything that can be automated so security experts can focus on complex attack paths and business logic flaws.
Understanding Security Testing Layers in CI/CD
Security testing is often misunderstood because multiple categories overlap.
| Testing Type | Purpose |
|---|---|
| SAST | Analyze source code |
| SCA | Detect vulnerable dependencies |
| DAST | Test running applications |
| IAST | Runtime security analysis |
| Penetration Testing | Simulate attacker behavior |
Penetration testing combines elements of all these approaches.
A mature CI/CD pipeline continuously performs automated penetration testing while reserving manual testing for sophisticated attack scenarios.
Designing a Security-First CI/CD Architecture
A security-centric pipeline typically looks like:
Developer Commit
↓
Pre-Commit Security Checks
↓
Pull Request Validation
↓
Build Stage
↓
Container Security Scan
↓
Infrastructure Validation
↓
Deploy to Staging
↓
Automated Penetration Testing
↓
Security Gate
↓
Production Deployment
Each stage eliminates vulnerabilities before they become more expensive to fix.
Stage 1: Pre-Commit Security Controls
The cheapest vulnerability is the one that never reaches Git.
Secret Detection
Install TruffleHog or Gitleaks before code reaches the repository.
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.20.0
hooks:
- id: gitleaks
Developer installation:
pip install pre-commit
pre-commit install
Now every commit is automatically scanned.
Dependency Security Validation
Use dependency auditing tools.
Python
pip install pip-audit
pip-audit
Node.js
npm audit --production
Go
govulncheck ./...
Stage 2: Automated Penetration Testing in Pull Requests
Pull requests provide the earliest opportunity to validate attack surfaces.
Authentication Testing
Example automated API validation:
import requests
response = requests.get(
"https://staging.example.com/api/admin"
)
assert response.status_code in [401,403]
This simple test catches accidental authorization bypasses.
Authorization Validation
Testing role separation:
admin_token = get_admin_token()
user_token = get_user_token()
admin = requests.get(
endpoint,
headers={"Authorization": f"Bearer {admin_token}"}
)
user = requests.get(
endpoint,
headers={"Authorization": f"Bearer {user_token}"}
)
assert admin.status_code == 200
assert user.status_code == 403
These tests often discover privilege escalation vulnerabilities before release.
Stage 3: Dynamic Application Security Testing (DAST)
DAST evaluates a running application exactly as attackers would.
OWASP ZAP Automation
Deploy the application into a temporary staging environment.
GitHub Actions example:
- name: OWASP ZAP Scan
uses: zaproxy/action-full-scan@v0.10.0
with:
target: "https://staging.example.com"
Baseline Scan
docker run -t owasp/zap2docker-stable zap-baseline.py \
-t https://staging.example.com
Findings may include:
- Missing security headers
- XSS exposure
- Cookie weaknesses
- Directory traversal
- Information disclosure
Stage 4: API Penetration Testing Automation
APIs have become the primary attack surface.
OpenAPI Security Testing
Tools like Schemathesis can automatically generate attack cases.
schemathesis run openapi.yaml \
--base-url=https://staging.example.com
Generated tests include:
- Invalid inputs
- Boundary conditions
- Injection attempts
- Authentication failures
Fuzz Testing
schemathesis run \
openapi.yaml \
--checks all
This uncovers hidden edge cases frequently missed by developers.
Stage 5: Container and Kubernetes Penetration Testing
Containers introduce a different attack surface.
Container Image Scanning
Trivy example:
trivy image myapp:latest
CI integration:
- name: Container Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
severity: HIGH,CRITICAL
Kubernetes Security Assessment
Using Kubescape:
kubescape scan framework nsa
Checks include:
- Privileged containers
- Host networking
- Excessive capabilities
- Missing security contexts
Stage 6: Infrastructure Penetration Testing
Infrastructure is code. It should be tested like code.
Terraform Security Validation
Checkov example:
checkov -d terraform/
GitHub Actions:
- name: Terraform Security Scan
uses: bridgecrewio/checkov-action@master
with:
directory: terraform
Cloud Configuration Testing
AWS example:
prowler aws
Findings include:
- Public S3 buckets
- Weak IAM policies
- Missing encryption
- Excessive permissions
Integrating Security Gates into CI/CD
Not every vulnerability should block deployment.
A practical policy:
| Severity | Action |
|---|---|
| Critical | Fail build |
| High | Fail production deployment |
| Medium | Ticket creation |
| Low | Backlog |
GitHub Actions gate:
- name: Fail on Critical Issues
run: |
if [ "$CRITICAL_FINDINGS" -gt 0 ]; then
exit 1
fi
Reporting, Dashboards, and Vulnerability Management
Security data scattered across tools creates chaos.
Centralize findings.
Popular platforms:
- DefectDojo
- Security Hub
- Grafana
- ELK Stack
Example DefectDojo import:
curl -X POST \
-H "Authorization: Token $TOKEN" \
-F "file=@zap-report.xml" \
https://defectdojo.example.com/api/v2/import-scan/
Building a Production-Ready DevSecOps Pipeline
Complete GitHub Actions workflow:
name: Continuous Security Testing
on:
pull_request:
push:
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep
uses: returntocorp/semgrep-action@v1
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy FS
run: trivy fs .
container-scan:
runs-on: ubuntu-latest
steps:
- name: Build Image
run: docker build -t app:${{ github.sha }} .
- name: Scan Image
run: trivy image app:${{ github.sha }}
iac-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov
run: checkov -d terraform/
dast:
needs:
- sast
- dependency-scan
- container-scan
- iac-scan
runs-on: ubuntu-latest
steps:
- name: OWASP ZAP
uses: zaproxy/action-full-scan@v0.10.0
with:
target: https://staging.example.com
This provides comprehensive automated penetration testing from commit to deployment.
Common Mistakes and Lessons Learned
Treating DAST as Penetration Testing
DAST is valuable but incomplete. Human attackers exploit business logic flaws that scanners cannot detect.
Running Every Scan on Every Commit
Excessive scanning creates developer fatigue.
Use:
- Fast scans on pull requests
- Full penetration testing on staging
- Deep assessments before production
Ignoring Authentication Testing
Many breaches result from authorization flaws rather than software vulnerabilities.
Focus heavily on:
- RBAC validation
- Token abuse testing
- API authorization checks
Failing to Prioritize Findings
Thousands of low-risk findings provide little value.
Security teams should prioritize:
- Critical
- High
- Exploitable
- Internet-facing
Everything else comes later.
Integrating penetration testing into CI/CD transforms security from a periodic activity into a continuous engineering practice. By combining pre-commit validation, SAST, dependency scanning, container assessment, infrastructure testing, API security analysis, and automated DAST, organizations can identify vulnerabilities at the earliest possible stage.
The strongest DevSecOps programs do not rely on a single security tool. They build layered defenses throughout the entire software delivery lifecycle, ensuring that every commit, build, deployment, and infrastructure change is evaluated through an attacker's lens before it reaches production.
Top comments (0)