HomeRoadmapsSecurity Day 3
Security Track Β· Day 3 Dynamic Scans Β· 20 min

Dynamic DAST & Attack Simulations
OWASP ZAP & API Fuzzing β€” Day 3

Execute automated OWASP ZAP baseline scans in Docker, simulate REST endpoint fuzzing attacks, and audit HTTP security headers against vulnerable-store-api.

✨ Agent: Claude 3.7 Sonnet / Gemini 3.5 Β· 200K contextπŸ›‘οΈ AI SecOps & Red-Teaming Architect
DASTOWASP ZAPAPI FuzzingSecurity HeadersHelmetRuntime Testing
About this lab

Static analysis alone cannot detect runtime configuration issues, such as missing response headers, cross-origin misconfigurations, or server-level parameter reflection. In this lab, you will runOWASP ZAP against the live running vulnerable-store-api container and execute automated attack fuzzing.

πŸ“¦Sample Codebase & Working Solution (Day 3)Available Now
View on GitHub

The official reference codebase for Day 3 is hosted in the repository. Clone the repository and navigate to day-3-dast-zap-fuzzing to run the working solution.

Git Clone β€” Working Solution
git clone https://github.com/letstrnsfrm-ai/security-compliance-roadmap.git
cd security-compliance-roadmap/day-3-dast-zap-fuzzing
🏭Production Context & Enterprise Implementation
πŸ’‘ Why We Are Doing This: Dynamic Application Security Testing (DAST) inspects the application from the attacker's black-box perspective, catching vulnerabilities introduced by framework middleware, routing engines, or reverse proxies.
🏒 Real-World Production Usecase: Running headless OWASP ZAP scans against ephemeral staging environments before releasing pull requests to production.
βš™οΈ How Implemented in Production: Dockerized zaproxy baseline container scanning staging ingress endpoints, exporting Markdown/JSON vulnerability summaries to PR review comments.
Phase 1

Start Live Target API with Endpoints to Attack

Add product search and checkout routes to server.js and run the service locally on port 3001.

Step 1.1: Add Search Endpoint
server.js (Add Search Endpoint)
// Add to server.js
app.get('/api/products/search', (req, res) => {
  const query = req.query.q || '';
  // Intentionally reflects query without encoding & missing security headers
  res.send(`<h1>Search Results for: ${query}</h1><p>0 items found.</p>`);
});

app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', uptime: process.uptime() });
});
Step 1.2: Start Service
Terminal β€” Start Target Service
node server.js
# Output: Store API running on port 3001
Phase 2

Execute OWASP ZAP Baseline Container Scan

Run OWASP ZAP via Docker to spider endpoints and audit for missing security headers, clickjacking defenses, and cross-site scripting indicators.

Step 2.1: Run ZAP Container
Docker β€” ZAP Baseline Scan
docker run --rm -t zaproxy/zap-stable zap-baseline.py -t http://host.docker.internal:3001 -r zap-report.html
Step 2.2: Inspect Findings
ZAP Scan Telemetry Output
WARN-NEW: Content Security Policy (CSP) Header Not Set [10038] x 2
WARN-NEW: Missing Anti-clickjacking Header (X-Frame-Options) [10020] x 2
WARN-NEW: X-Content-Type-Options Header Missing [10021] x 2
WARN-NEW: Strict-Transport-Security (HSTS) Header Not Set [10035] x 2
Phase 3

Simulate Parameter Fuzzing & Payload Injections

Direct an automated curl fuzzing script to inject XSS and SQLi boundary payloads into the search route and assert response behaviors.

Step 3.1: Build Automated Fuzzer
scripts/fuzz-test.js
#!/usr/bin/env node
const http = require('http');

const payloads = [
  "<script>alert('xss')</script>",
  "' OR '1'='1",
  "../../../../etc/passwd",
  "%00%27%22",
];

async function testPayload(payload) {
  return new Promise((resolve) => {
    const url = `http://localhost:3001/api/products/search?q=${encodeURIComponent(payload)}`;
    http.get(url, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        const reflectsRawPayload = data.includes(payload);
        resolve({ payload, status: res.statusCode, reflectsRawPayload });
      });
    });
  });
}

async function runFuzzSuite() {
  console.log('⚑ Running Automated DAST Endpoint Fuzzer...');
  let flawsFound = 0;
  for (const p of payloads) {
    const result = await testPayload(p);
    if (result.reflectsRawPayload) {
      console.error(`🚨 DAST VULNERABILITY: Raw payload reflected unescaped! [${p}]`);
      flawsFound++;
    }
  }

  if (flawsFound > 0) {
    console.error(`\n❌ Fuzzing Failed: ${flawsFound} unencoded injections detected.`);
    process.exit(1);
  }
  console.log('βœ… Fuzzing Passed: All inputs properly encoded or rejected.');
}

runFuzzSuite();
Step 3.2: Execute Fuzz Test
Terminal β€” Run Fuzzer
node scripts/fuzz-test.js
# Output: 🚨 DAST VULNERABILITY: Raw payload reflected unescaped! [<script>alert('xss')</script>]
Phase 4

Harden HTTP Headers & Secure Response Encoding

Install Helmet middleware to inject critical HTTP headers and sanitize reflected HTML output to pass both ZAP and fuzz testing.

Step 4.1: Apply Helmet Hardening
server.js (Harden with Helmet)
// npm install helmet
const helmet = require('helmet');

// Enable standard security headers: CSP, HSTS, X-Frame-Options, noSniff
app.use(helmet());

// Secure Search Route with HTML entities encoding
app.get('/api/products/search', (req, res) => {
  const query = String(req.query.q || '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;');

  res.send(`<h1>Search Results for: ${query}</h1><p>0 items found.</p>`);
});
Step 4.2: Verify Fuzz Suite Green
Terminal β€” Verify Fuzz Suite
node scripts/fuzz-test.js
# Output:
# ⚑ Running Automated DAST Endpoint Fuzzer...
# βœ… Fuzzing Passed: All inputs properly encoded or rejected.
Day 3 Key Learnings & Outcomes
  • Understood Dynamic Application Security Testing (DAST) principles and when black-box scanning is necessary.
  • Spun up an automated OWASP ZAP baseline scan in Docker against vulnerable-store-api.
  • Identified missing HTTP response headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options).
  • Wrote a dynamic payload fuzzer script (scripts/fuzz-test.js) and hardened the API using helmet middleware and output sanitization.

🧠 Knowledge Check

What is the primary difference between passive DAST scanning and active DAST scanning?