Security After Deployment Fails
Security that happens after code ships is too late. By then, the vulnerability is live. Users are at risk.
Modern security is automated, continuous, and happens during development. Scan every commit. Fail builds that have high-severity vulnerabilities. Security is a developer responsibility, not an afterthought.
The Security Scanning Stack
SAST (Static Application Security Testing): Analyze source code for vulnerabilities.
- Runs on code, no compilation needed.
- Fast (minutes).
- High false positive rate.
- Catches: SQL injection, XSS, hardcoded secrets, weak crypto.
DAST (Dynamic Application Security Testing): Test running application by attacking it.
- Runs after deployment.
- Slow (15-30 minutes).
- Tests real behavior (more accurate).
- Catches: misconfigurations, broken authentication, business logic flaws.
Dependency scanning: Check third-party libraries for known vulnerabilities.
- Runs on package manifests (package.json, requirements.txt, pom.xml).
- Very fast (<1 minute).
- High value (dependencies are large attack surface).
- Catches: outdated packages with known CVEs.
Container scanning: Check Docker images for vulnerabilities.
- Scans layers for malicious content and CVEs.
- Fast (seconds).
- Essential for container-based infrastructure.
- Catches: vulnerable base images, malware.
SAST Tools
Semgrep (open-source):
- Lightweight, fast, accurate.
- Works with 15+ languages.
- Integrates easily into CI/CD.
- Best for startups.
# Run on every commit
semgrep --config=p/security-audit src/
# Fails if high-severity issues found
SonarQube:
- More comprehensive than Semgrep.
- Expensive ($2k+/year).
- Better for enterprises.
Snyk, GitHub Advanced Security:
- Managed SaaS.
- Easy integration with GitHub/GitLab.
- Paid services.
Dependency Scanning
npm audit (Node.js):
npm audit # Find vulnerabilities
npm audit fix # Auto-fix
pip audit (Python):
pip install pip-audit
pip-audit # Find vulnerabilities in requirements
Safety (Python):
pip install safety
safety check
OWASP Dependency-Check:
dependency-check --scan .
Integrate into CI/CD:
# GitHub Actions
- name: Audit dependencies
run: npm audit --audit-level=high
# Fail if high-severity vulnerabilities
Container Scanning
Trivy:
- Fast, accurate, open-source.
- Scans Docker images, Kubernetes manifests, any files.
- Integrates with CI/CD.
trivy image myapp:latest
# Outputs CVEs and severity
Snyk Container:
- Managed scanning.
- Better UX, paid.
Anchore:
- Open-source or managed.
- Deep analysis of image layers.
Fail builds if critical CVEs found:
- name: Scan image
run: |
trivy image myapp:latest
# Fails if critical CVEs found
DAST and Penetration Testing
DAST requires a running application. Run after staging deployment.
OWASP ZAP (open-source):
docker run -v $(pwd):/zap/wrk owasp/zap2docker-stable zap-baseline.py -t https://staging.myapp.com/
Reports vulnerabilities in running app.
Real penetration testing: For production applications, hire professional pen testers annually. Automated DAST catches low-hanging fruit; professionals find business logic flaws and nuanced attacks.
CI/CD Security Pipeline
Ideal security automation:
# .github/workflows/security.yml
name: Security Scan
on: [pull_request]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: SAST scan
run: semgrep --config=p/security-audit src/
dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Npm audit
run: npm audit --audit-level=high
- name: OWASP dependency check
run: dependency-check --scan .
secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Detect secrets
uses: trufflesecurity/trufflehog@main
container:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan image
run: trivy image myapp:${{ github.sha }}
On every PR:
- SAST scans source code
- Dependency check scans packages
- Secret detection prevents credential leaks
- Container scanning checks Docker image
If any check fails, PR is blocked. Fix issues before merging.
False Positives and Alert Fatigue
Security scanning generates false positives. ("This is SQL injection! Actually, it's a log message.") Too many false positives cause developers to ignore alerts.
Manage false positives:
- Use strict SAST rules (reduce noise)
- Suppress known false positives with comments
# nosemgrep: sql-injection
# The user input is validated and parameterized above
query = f"SELECT * FROM users WHERE id = {user_id}"
- Fail the build only on high-severity issues
- Allow warnings and medium issues, but don't block
Policies and Compliance
Document security policies:
- No hardcoded secrets
- All dependencies must be pinned to specific versions
- High-severity vulnerabilities must be fixed within 48 hours
- Medium-severity within 1 week
- All Docker images must be scanned before production
Enforce policies in CI/CD automatically.
Security Checklist
- SAST (Semgrep or SonarQube) in CI/CD
- Dependency scanning (npm audit, OWASP DC)
- Secret scanning (TruffleHog or GitHub Secret Scanning)
- Container scanning (Trivy)
- Secrets management (no hardcoded credentials)
- DAST for critical services (after staging deploy)
- Annual penetration testing for production
- Documented security policies
- Security training for team
- Incident response plan
Frequently asked questions
Should we scan every commit or just on release?
Every commit, in CI/CD. The earlier you catch vulnerabilities, the cheaper they are to fix. Scanning only at release means vulnerabilities reach production. Scan on every PR.
How do we handle unavoidable vulnerabilities (e.g., library with unpatched CVE)?
Document the risk. If the CVE doesn't affect your code path, document why it's safe. Mitigate with compensating controls (WAF rules, network isolation). Replace the library ASAP. Never ignore.
What's the difference between SAST and DAST?
SAST analyzes code without running it (fast, catches code flaws). DAST tests running application (slow, catches runtime issues and misconfigurations). Use both. SAST for speed, DAST for depth.