Appearance
OWASP ZAP — Dynamic Application Security Testing
OWASP ZAP (Zed Attack Proxy) performs Dynamic Application Security Testing (DAST) by sending real HTTP requests to a running instance of the application and analysing responses for security vulnerabilities. Unlike SAST, DAST finds issues that only manifest at runtime.
DAST vs SAST
| Dimension | SAST (SonarCloud) | DAST (ZAP) |
|---|---|---|
| When | At source code level | Against a live running app |
| What it finds | Code-level bugs, insecure patterns | Runtime injection, auth bypass, misconfigs |
| False-positive rate | Medium | Higher — requires tuning |
| Speed | Fast (minutes) | Slow (10–60 min per scan) |
| Target environment | Any — runs offline | Requires a deployed environment |
Target Environment
DAST Runs Against Stage Only
ZAP DAST runs exclusively against the stage environment (microtecstage.com). It does NOT run against dev (too unstable) or production (risk of disruption). UAT scans are run manually on demand before major releases.
| Property | Value |
|---|---|
| Target URL | https://gateway.microtecstage.com |
| Pipeline stage | Stage 13 — DAST (after stage deployment) |
| Scan type | Passive scan always; Active scan on stage branch only |
| Report format | HTML + JSON (both published as artefacts) |
| Gate | Pipeline fails on High severity findings |
Passive vs Active Scan
Passive Scan
ZAP acts as a proxy and observes traffic without sending additional requests. It detects:
- Missing security headers (
Content-Security-Policy,X-Frame-Options,Strict-Transport-Security) - Cookie flags missing (
HttpOnly,Secure,SameSite) - Information disclosure in response headers (server version, stack traces)
- Insecure redirect chains
Passive scanning is read-only — it cannot cause side effects and is safe to run against any environment.
Active Scan
ZAP actively probes endpoints by injecting payloads. It detects:
- SQL Injection
- Cross-Site Scripting (XSS)
- Path traversal
- Server-Side Request Forgery (SSRF)
- Remote code execution vectors
- Authentication bypass
Active Scan Side Effects
Active scanning sends malicious payloads to the application. Never run an active ZAP scan against production. Ensure stage test data is non-sensitive before running active scans. Some active scan rules (e.g. buffer overflow checks) can crash under-protected endpoints.
Pipeline Integration
yaml
- stage: DAST
displayName: 'Stage 13 - DAST (OWASP ZAP)'
dependsOn: DeployStage
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/stage'))
jobs:
- job: ZAPScan
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Bash@3
displayName: 'Run ZAP Passive Scan'
inputs:
targetType: inline
script: |
docker run --rm \
-v "$(Build.ArtifactStagingDirectory):/zap/wrk:rw" \
ghcr.io/zaproxy/zaproxy:stable \
zap-baseline.py \
-t "https://gateway.microtecstage.com" \
-r zap-report.html \
-J zap-report.json \
-c zap-rules.conf \
-I # don't fail on warnings, only on FAIL rules
- task: Bash@3
displayName: 'Run ZAP Active Scan'
condition: eq(variables['Build.SourceBranch'], 'refs/heads/stage')
inputs:
targetType: inline
script: |
docker run --rm \
-v "$(Build.ArtifactStagingDirectory):/zap/wrk:rw" \
ghcr.io/zaproxy/zaproxy:stable \
zap-full-scan.py \
-t "https://gateway.microtecstage.com" \
-r zap-full-report.html \
-J zap-full-report.json \
-c zap-rules.conf
- task: PublishBuildArtifacts@1
displayName: 'Publish ZAP Reports'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'zap-dast-reports'
publishLocation: 'Container'ZAP Rules Configuration
The zap-rules.conf file controls which alerts cause pipeline failures vs warnings vs ignored:
# zap-rules.conf
# Format: rule_id FAIL/WARN/IGNORE description
10016 WARN Web Browser XSS Protection Not Enabled
10017 WARN Cross-Domain JavaScript Source File Inclusion
10019 WARN Content-Type Header Missing
10020 FAIL X-Frame-Options Header Not Set
10021 FAIL X-Content-Type-Options Header Missing
10038 FAIL Content Security Policy (CSP) Header Not Set
10040 FAIL Secure Pages Include Mixed Content
10054 FAIL Cookie Without SameSite Attribute
10055 FAIL CSP Scanner
10096 FAIL Timestamp Disclosure - Unix
40012 FAIL Cross Site Scripting (Reflected)
40014 FAIL Cross Site Scripting (Persistent)
40018 FAIL SQL Injection
40019 FAIL SQL Injection - MySQL
40024 FAIL SQL Injection - SQLite
90022 WARN Application Error DisclosureRules set to FAIL break the pipeline. Rules set to WARN are reported but do not fail the build. Rules set to IGNORE are suppressed.
Report Format
HTML Report
The HTML report is human-readable and includes:
- Summary table (High / Medium / Low / Informational counts)
- Per-alert detail with request/response pairs
- OWASP classification (OWASP Top 10 mapping)
- Solution recommendations
JSON Report
The JSON report is machine-readable for integration with dashboards:
json
{
"site": [{
"name": "https://gateway.microtecstage.com",
"alerts": [{
"pluginid": "10038",
"alertRef": "10038-1",
"alert": "Content Security Policy (CSP) Header Not Set",
"name": "Content Security Policy (CSP) Header Not Set",
"riskcode": "2",
"confidence": "3",
"riskdesc": "Medium (High)",
"count": "14",
"solution": "Ensure that your web server..."
}]
}]
}Risk codes: 3 = High, 2 = Medium, 1 = Low, 0 = Informational.
False Positive Management
DAST produces more false positives than static analysis. The process for managing them:
Step 1 — Triage
For each High or Medium finding in the ZAP report:
- Reproduce manually using Burp Suite or curl
- Confirm the endpoint is actually vulnerable (not a false positive)
- Check if the issue already has a tracking ticket
Step 2 — Suppress Known False Positives
Add confirmed false positives to zap-rules.conf with a comment explaining why:
# FALSE POSITIVE: /api/v1/health returns 200 with no body — ZAP flags as info disclosure
# Confirmed safe 2024-01-15 by @security-team
90022 IGNORE Application Error DisclosureStep 3 — Fix Real Findings
| Severity | SLA | Action |
|---|---|---|
| High | Block deployment, fix within 24h | Create P1 ticket, assign to service owner |
| Medium | Fix within sprint | Create P2 ticket |
| Low | Fix within quarter | Backlog item |
| Informational | Best effort | Tech debt backlog |
Authenticated Scans
By default ZAP scans public endpoints only. For authenticated scan coverage, configure ZAP with a service account JWT via the CONTEXT_FILE option. This is done for the /api/v1/ ERP endpoints using a dedicated zap-scanner Keycloak service account in the stage realm.
Scan Coverage Map
| Endpoint Group | Passive | Active |
|---|---|---|
/api/v1/ (ERP APIs) | Yes | Yes (authenticated) |
/health, /health/ready | Yes | No |
| Gateway routing layer | Yes | No |
Keycloak /auth/ endpoints | Yes | No (Keycloak manages its own security) |
| Static frontend assets | Yes | No |