Security Testing
Integrate security testing into your development workflow - SAST with Semgrep, dependency scanning, OWASP ZAP DAST, and threat modeling basics.
skill: Security Testing category: Engineering tags: [Security Testing, OWASP, SAST, DAST, Penetration Testing] readingTime: 4
Security testing should be automatic, not manual. A security researcher finding a vulnerability after launch is 100× more expensive than a CI check finding it before. Shift security left - build SAST, dependency scanning, and basic penetration testing into the CI pipeline. Reserve manual penetration testing for critical pre-launch audits.
Workflow
- Add SAST with SemgrepStatic Application Security Testing (SAST) analyzes source code for vulnerabilities without executing it. Semgrep uses pattern matching to find SQL injection, XSS, hardcoded secrets, and framework-specific issues.
- Scan dependencies for vulnerabilitiesDependencies are the most common source of security vulnerabilities. npm audit, Snyk, and Trivy automatically identify known CVEs in your dependency tree.
- Test for OWASP Top 10 vulnerabilitiesThe OWASP Top 10 covers the most critical security risks. Writing specific security test cases prevents regression of these known vulnerabilities.
- Run DAST with OWASP ZAPDynamic Application Security Testing (DAST) scans a running application, simulating attacks that static analysis misses - timing attacks, race conditions, and configuration issues.
- Add security headers and reviewSecurity headers protect against common browser-based attacks. A security headers audit catches missing protections before they're exploited.
Output Format
Security testing: Semgrep SAST with p/owasp-top-ten, Trivy image scan with --exit-code 1 for CRITICAL, OWASP ZAP baseline scan on staging, security test cases for OWASP A1/A3/A7/A9, and helmet.js with CSP + HSTS.
semgrep --config=auto --config=p/owasp-top-ten src/
trivy fs . --severity HIGH,CRITICAL --exit-code 1
zaproxy/action-baseline → staging URL → fail_action:true
Test: 403 for wrong user, bcrypt hash, SQL injection params, no password in response
helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"] } } })Examples
Edge Cases & Gotchas
- False positives in SAST - SAST tools generate false positives. Use inline suppressions (// nosemgrep: rule-id) for documented false positives. Review suppressions in PR - require comments explaining why it's safe.
- DAST and authenticated endpoints - ZAP needs a valid auth token to test authenticated endpoints. Configure ZAP's authentication with a script that logs in and maintains session: zap-auth-script.js.
- Dependency scanning false positives - Some CVEs in transitive dependencies are in code paths your app never exercises. Triage with Snyk's reachability analysis - it identifies which CVEs are in code paths actually called by your application.
- Content Security Policy and third-party scripts - CSP breaks existing third-party integrations (analytics, chat, payment forms). Use Report-Only mode first to collect violations: Content-Security-Policy-Report-Only. Fix all violations, then switch to enforcement mode.
When to Break These Rules
- Commission a manual penetration test instead of (or in addition to) DAST for applications handling sensitive financial, medical, or government data - automated tools miss business logic vulnerabilities.
- Skip ZAP scanning in PR CI for speed - run it nightly on staging. Use Semgrep SAST in PR CI (fast, inline) and ZAP on a separate schedule (slow, but catches what SAST misses).
Reference Files
https://semgrep.dev/docs/https://owasp.org/www-project-top-ten/