Executive Definition
Security testing is the systematic evaluation of a system's ability to protect confidentiality, integrity, and availability against malicious inputs and misconfigurations. It combines static analysis of source code, dynamic probing of running applications, dependency vulnerability scanning, and manual penetration testing. The reference threat catalogue is the OWASP Top 10 for web applications and the OWASP API Security Top 10 for services.
The categories map to distinct testing techniques. Static application security testing (SAST) reads source code for insecure patterns — SQL string concatenation, unbounded reflection, hardcoded secrets. Dynamic application security testing (DAST) probes the running application with crafted requests to find injection, broken auth, and misconfigurations. Interactive application security testing (IAST) instruments the runtime to detect vulnerabilities as they execute. Software composition analysis (SCA) scans third-party dependencies against known-CVE databases.
None of these tools replaces manual penetration testing. Automated scanners find well-known patterns; skilled testers find novel logic flaws — a discount code that stacks with itself, a race condition in a two-step withdrawal, an ID-substitution attack on a bulk-export endpoint. A mature programme uses automation to keep the floor from sinking and pen-testing to raise the ceiling on hard-to-find defects.
Shift-left security is the practice of moving these checks as early in the SDLC as possible. In 2026 a typical pipeline runs SAST and SCA in CI on every PR, DAST against staging nightly, IAST during integration tests, and pen-tests before each major release or on a quarterly cadence. Findings are triaged by severity (CVSS score plus exploitability) and routed to owners with fix SLAs.
Security testing is where compliance meets craft. Frameworks like SOC 2, ISO 27001, PCI-DSS, and HIPAA all require documented security testing, and the auditors will ask for evidence: pipeline logs, scan reports, remediation tickets. Design your programme so that the evidence falls out naturally — versioned scan configs, immutable log storage, and a security backlog that produces the report an auditor wants without extra ceremony.
Architecture & Production Code
A layered security testing pipeline runs different tools at different stages. Each has a distinct place in the SDLC and a distinct feedback loop.
Developer laptop CI (PR) Staging Prod-like
┌─────────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ git secrets │ ────▶ │ SAST (Semgrep,│ ───▶ │ DAST (OWASP │ ───▶ │ Pen-test │
│ pre-commit hook │ │ CodeQL) │ │ ZAP, Burp) │ │ (quarterly) │
└─────────────────┘ │ SCA (Snyk, │ │ IAST (Contrast│ │ Bug bounty │
│ Dependabot) │ │ Security) │ │ (continuous) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────┐
│ Security backlog (severity, CVSS, SLA, owner) │
└──────────────────────────────────────────────────────┘The developer laptop is the cheapest place to catch a secret leak. Pre-commit hooks (git-secrets, trufflehog) prevent tokens from ever entering history, which is far easier than rotating them after a push.
CI is where SAST and SCA belong. Both are fast enough to gate merges without slowing the developer loop. Set severity thresholds so only high-severity new findings block; low-severity findings go to the backlog with a sensible SLA (e.g. 30 days for medium, 90 for low).
DAST and IAST run against a deployed environment, which is why they belong in nightly staging jobs rather than PR gates. Configure ZAP or Burp Enterprise with an authenticated session so it can probe post-login endpoints; unauthenticated scans miss most of the real surface.
name: Security
on:
pull_request:
branches: [main]
schedule:
- cron: "0 2 * * *" # nightly DAST
workflow_dispatch:
jobs:
sast:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: returntocorp/semgrep-action@v1
with:
config: p/owasp-top-ten
severity: ERROR,WARNING
sca:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high --fail-on=upgradable
dast:
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
steps:
- uses: actions/checkout@v4
- name: OWASP ZAP baseline scan
uses: zaproxy/action-baseline@v0.12.0
with:
target: "https://staging.example.com"
cmd_options: "-a -j -m 5"
fail_action: false
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: zap-report
path: report_html.htmlSAST vs DAST vs IAST vs SCA vs Pen-Test
| Aspect | SAST | DAST | IAST | SCA | Pen-Test |
|---|---|---|---|---|---|
| Layer | Source code | Running app | Instrumented runtime | Dependencies | Everything |
| Where it runs | CI | Staging | Integration tests | CI | Human-driven |
| Finds | Insecure patterns | Injection, misconfig | Runtime data flow | Vuln libraries | Logic flaws |
| Speed | Fast (minutes) | Slow (hours) | Medium | Fast | Days–weeks |
| False-positive rate | Medium | Medium-high | Low | Low | Low |
| Common tools | Semgrep, CodeQL | ZAP, Burp | Contrast, Seeker | Snyk, Dependabot | Human + Burp Pro |
No single technique is sufficient. SAST/SCA hold the floor cheaply on every PR; DAST/IAST catch the runtime issues that only manifest against a real environment; pen-testing surfaces the logic flaws automation cannot infer. Cut any layer and a whole class of defect ships.
Production Debugging Scenarios
Security tooling produces noisy reports. Three patterns explain most of the noise and how to quiet it responsibly.
SAST floods PRs with legacy findings
- Symptom
- Every PR shows 400 SAST alerts from unchanged code; developers ignore them all.
- Root cause
- Threshold gates on total findings rather than PR delta.
- Fix
- Configure the scanner to fail only on new findings introduced by the PR. Snapshot the baseline of legacy findings and track their burn-down separately.
DAST scan misses post-login endpoints
- Symptom
- Nightly ZAP report is clean; a manual test finds an IDOR on /api/orders/{id}.
- Root cause
- ZAP was run unauthenticated, so it never probed authenticated routes.
- Fix
- Configure ZAP with a scripted auth flow or an injected session cookie, and mark authenticated URLs in the context so they are actively scanned.
SCA reports critical CVE in a transitive dependency
- Symptom
- Snyk flags a Log4j-style CVE in a package no one recognises.
- Root cause
- A direct dependency pulls in the vulnerable version transitively; a straight upgrade breaks other consumers.
- Fix
- Use npm/Yarn overrides or Maven dependencyManagement to pin the transitive version to a patched release. Reproduce the CVE in a test to confirm the fix.
Practice this concept in a real QA interview
Run a live mock with our AI Interview Coach, tune your resume with the ATS Resume Reviewer, and screen live listings on the QA Jobs Radar.