Module 7 ended with a promise: we had the complete process assembled -S-SDLC, threat modeling, DevSecOps, training and a tooling stack for BazarNube- and the moment had come to apply it hands-on. This module keeps that promise. Across these four lessons we stop describing the process and start executing it on BazarNube: two guided exercises on identification and remediation, plus two case studies on incident analysis and security improvement. We begin at the starting point of any AppSec job: finding what is wrong. In this lab you receive a real slice of the application -several Node/Express endpoints, a React component and its configuration- and your task is to identify, classify and document every vulnerability the way an analyst would, combining code review and scanning with ZAP (covered in depth in module 6). Do not fix anything yet: that is exercise 2. Here we only hunt and catalog.

Contents

  1. Objective and lab environment
  2. Methodology: how to approach identification
  3. The Top Ten and ASVS based checklist
  4. The code to review: endpoints, component and configuration
  5. How to document a finding and log it in the backlog
  6. Common mistakes and tips
  7. Exercises
  8. Conclusion

Objective and lab environment

You work as AppSec at BazarNube alongside Lucía (backend lead) and Marc (frontend). SRE has deployed a new branch of the orders and catalog service to staging, and before approving the merge you have to review it. You have two sources of information:

  • The source code for the slice (below), on which you will do a manual review.
  • A ZAP scan of the staging instance already running, whose report you will consult to confirm findings and uncover those the code does not reveal at a glance.

The goal of the lab is not to exploit anything in depth, but to identify and classify: for each problem, determine its OWASP Top Ten 2021 category, its severity, the evidence that backs it and the ASVS requirement it violates. The result is a list of findings ready to enter the BZN-xxx backlog, exactly the format ZAP was already feeding in 06-03.

Ethical reminder: all of this is done on our application in our staging. Identifying vulnerabilities is only legitimate on your own systems or with explicit authorization, as we established in module 1.

Methodology: how to approach identification

Improvising leads to blind spots. We follow a repeatable method that combines both techniques:

graph LR
    A[Understand the context] --> B[Checklist-driven code review]
    B --> C[Passive and active ZAP scan]
    C --> D[Correlate code and alerts]
    D --> E[Triage: confirm or discard]
    E --> F[Document each BZN finding]
  1. Understand the context. What does this code do? What data does it handle? BazarNube deals with orders, prices, personal data and payments: any flaw here touches money or PII.
  2. Checklist-driven code review. Do not read the code "to see what turns up"; walk it with a list of concrete questions (next section). Pay special attention to the trust boundary crossings from the 07-02 threat model: user input, database queries, third-party calls.
  3. ZAP scan. The passive scan detects misconfigured headers and cookies; the active scan tests injection, XSS or path traversal. We do not re-explain ZAP: we use it as in 06-03.
  4. Correlate. Every ZAP alert should be pinpointable in the code, and every code-level suspicion should be confirmed dynamically where possible. What shows up through both paths is almost always real.
  5. Triage. Discard false positives with evidence (reproduce the request), not on a hunch.
  6. Document. A finding without a reproducible record does not exist for the team.

The Top Ten and ASVS based checklist

This is the script of questions we use to walk the code. Each row points to a Top Ten category and to the ASVS chapters that verify that control.

# Review question Top Ten ASVS
1 Is it checked that the user owns the object being requested (order, invoice)? A01 V4 (Access Control)
2 Does any query concatenate user input into SQL/commands? A03 V5 (Validation/Encoding)
3 Is user content rendered as HTML without escaping? A03 V5
4 Are there embedded secrets in the code or weak cryptographic algorithms? A02 V6 (Cryptography)
5 Does the app make requests to URLs the user controls? A10 V12 (SSRF)
6 Are files accessed by names that come from the user? A01 V4, V12
7 Are security headers (CSP, HSTS) or helmet missing? A05 V14 (Config)
8 Do cookies carry HttpOnly, Secure and SameSite? A05 V3 (Session)
9 Do errors expose stack traces or internal details? A05 V7 (Errors/Logging)
10 Is there rate limiting on authentication and sensitive endpoints? A07 V2 (Authentication)

The code to review: endpoints, component and configuration

Below is the slice we were handed. Read it with the checklist in hand before looking at the solution.

config.js (backend configuration)

// config.js — orders service configuration
module.exports = {
  jwtSecret: 'bazarnube-2021',        // used to sign session tokens
  jwtAlg: 'HS256',
  db: { host: 'db', user: 'app', password: 'app', ssl: false },
  cookie: { httpOnly: false, secure: false }, // session cookie options
};

app.js (Express bootstrap)

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

app.use(express.json());
app.use(cookieParser());
// (helmet is not installed and no Content-Security-Policy is defined)

app.use(require('./routes/orders'));
app.use(require('./routes/catalog'));

// Global error handler
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message, stack: err.stack }); // internal detail sent to the client
});

app.listen(3000);

routes/orders.js

const router = require('express').Router();
const db = require('../db');
const path = require('path');
const auth = require('../middleware/auth'); // validates the JWT and sets req.user

// Order detail
router.get('/api/orders/:id', auth, async (req, res) => {
  const { rows } = await db.query('SELECT * FROM orders WHERE id = $1', [req.params.id]);
  res.json(rows[0]);   // returns the order without checking it belongs to the user
});

// Invoice PDF download
router.get('/api/invoices', auth, (req, res) => {
  const file = req.query.file; // e.g. ?file=2026-000123.pdf
  res.sendFile(path.join('/var/bazarnube/invoices', file));
});

module.exports = router;

routes/catalog.js

const router = require('express').Router();
const db = require('../db');
const auth = require('../middleware/auth');

// Product search
router.get('/api/products/search', async (req, res) => {
  const q = req.query.q;
  const sql = `SELECT id, name, price FROM products WHERE name LIKE '%${q}%'`;
  const { rows } = await db.query(sql);  // q is concatenated directly
  res.json(rows);
});

// Import product: downloads the image from a URL supplied by the seller
router.post('/api/products/import', auth, async (req, res) => {
  const { imageUrl } = req.body;
  const resp = await fetch(imageUrl); // downloads whatever URL the user sends
  const buffer = Buffer.from(await resp.arrayBuffer());
  // ... stores the buffer as the product image
  res.json({ ok: true });
});

module.exports = router;

ProductReviews.jsx (React component)

export function ProductReviews({ reviews }) {
  // reviews[].body is free text written by other shoppers
  return (
    <ul>
      {reviews.map((r) => (
        <li key={r.id} dangerouslySetInnerHTML={{ __html: r.body }} />
      ))}
    </ul>
  );
}

Excerpt from the ZAP report (staging)

The 06-03 scan against this branch returned, among others, these passive and active alerts:

[High]   SQL Injection             GET /api/products/search (q)
[High]   Path Traversal            GET /api/invoices (file)
[Medium] CSP: Header Not Set        /
[Low]    Cookie No HttpOnly Flag    Set-Cookie: session
[Low]    Application Error Disclosure  500 with stack trace

How to document a finding and log it in the backlog

A useful finding is reproducible and actionable. Each BZN-xxx record includes the same fields ZAP already gave us, plus the ASVS requirement it violates:

  • ID: BZN-xxx.
  • Title: what it is, in one line.
  • OWASP category: A01–A10 of the Top Ten 2021.
  • Severity: Critical/High/Medium/Low (by risk = impact x likelihood).
  • Location: file/endpoint and line.
  • Evidence: the request or code fragment that proves it.
  • ASVS requirement: the control it violates (for exercise 2).
  • How it was detected: code review, ZAP, or both (higher confidence).

Example of a well-written record:

ID:          BZN-101
Title:       IDOR in GET /api/orders/:id (missing ownership check)
Category:    A01 Broken Access Control
Severity:    High (access to PII and other customers' orders)
Location:    routes/orders.js, GET /api/orders/:id handler
Evidence:    Authenticated as customer A, GET /api/orders/778 (B's order)
             returns 200 with B's data. Not filtered by req.user.id.
ASVS:        V4.1.1 / V4.2.1 (object-level authorization)
Detection:   Code review (ZAP does not flag it: requires business logic)

Note the nuance in the last line: ZAP does not detect the IDOR because it does not know who should be able to see what. Authorization logic flaws are almost always caught by code review, whereas injection, XSS or path traversal also surface in the dynamic scan. That is why the method combines both techniques: neither one alone is enough.

Common Mistakes and Tips

  • Trusting the scanner alone. ZAP does not find IDOR, embedded secrets or weak cryptography. If your identification is limited to the ZAP report, you will miss A01 and much of A02. Always combine it with code review.
  • Mistaking quantity for quality. Reporting a hundred trivial passive alerts buries the two genuinely critical ones. Prioritize by real risk, as in the 06-03 triage.
  • Not reproducing before reporting. A finding without reproducible evidence gets debated forever. Attach the request or the exact line.
  • Ignoring dangerouslySetInnerHTML. React escapes by default, so many reviewers assume "there is no XSS." That specific API disables the protection: it is an A03 magnet.
  • Tip: always review the trust boundary crossings first (user input, database queries, third-party calls, file access). That is where the vast majority of findings live, as the 07-02 threat model anticipated.

Exercises

Exercise 1. Walk the slice with the checklist and produce the complete list of findings: for each one, give the endpoint/file, the Top Ten 2021 category and the severity. You should find at least nine.

Exercise 2. For the GET /api/invoices endpoint, write the complete BZN-140 record (all fields) and state the concrete payload you would use as evidence.

Exercise 3. Explain why the orders IDOR does not appear in the ZAP report and which technique does detect it. Generalize: which Top Ten categories does a DAST structurally miss?

Solutions

Solution 1. List of lab findings:

ID Finding Location OWASP 2021 Severity Detection
BZN-134 SQLi via concatenation of q catalog.js /search A03 Injection Critical Code + ZAP
BZN-101 IDOR: another user's order orders.js /orders/:id A01 Broken Access Control High Code
BZN-140 Path traversal in file= orders.js /invoices A01 Broken Access Control High Code + ZAP
BZN-131 SSRF: download of arbitrary URL catalog.js /import A10 SSRF High Code
BZN-087 Stored XSS via dangerouslySetInnerHTML ProductReviews.jsx A03 Injection High Code
BZN-155 Embedded and weak JWT secret config.js A02 Cryptographic Failures High Code
BZN-041 No CSP or helmet app.js A05 Security Misconfiguration Medium ZAP
BZN-039 Cookie without HttpOnly/Secure/SameSite config.js A05 Security Misconfiguration Medium ZAP
BZN-060 Stack trace exposed to the client app.js (error handler) A05 Security Misconfiguration Low Code + ZAP

Several (BZN-140, BZN-131, BZN-087, BZN-041, BZN-039, BZN-060) already existed in the backlog from the 06-03 scan: this exercise confirms them by code review and adds two new ones (BZN-134, BZN-101).

Solution 2. BZN-140 record:

ID:          BZN-140
Title:       Path Traversal in GET /api/invoices (file parameter)
Category:    A01 Broken Access Control
Severity:    High (arbitrary file read on the server)
Location:    routes/orders.js, GET /api/invoices handler
Evidence:    GET /api/invoices?file=../../../../etc/passwd  -> 200 with the file
             sendFile joins the path without normalizing or validating that it
             stays inside /var/bazarnube/invoices.
ASVS:        V4.1.3 / V12.3.1 (file access control, canonicalized path)
Detection:   Code review + ZAP active "Path Traversal" alert

The evidence payload is ?file=../../../../etc/passwd (or any path outside the invoices directory). It confirms arbitrary read.

Solution 3. ZAP does not detect the IDOR because a DAST tests inputs and responses without knowing the business rules: it does not know that order 778 belongs to another user, so a 200 looks correct to it. Detecting it requires understanding the authorization logic, which is done by code review or with manual authenticated tests using two users. In general, a DAST structurally misses: A01 (access control/IDOR/escalation), much of A02 (secrets and weak crypto in the code), A04 (design flaws) and A08 (integrity), because they depend on context and logic, not on patterns observable in the response.

Conclusion

We have turned a slice of BazarNube into a list of nine prioritized findings, each with its Top Ten category, its severity, its evidence and the ASVS requirement it violates, all logged as BZN-xxx records in the backlog. What matters is not just the list, but the method: context, Top Ten/ASVS checklist, code review, ZAP scan and correlation, with the key lesson that no single technique is enough -the scanner does not see the IDOR, and manual review does not scale like the scanner. Now we have the diagnosis; the cure is missing. In the next lesson, 08-02, we take exactly these nine records and remediate them one by one: corrected code, mapping to ASVS requirements and a re-scan to verify that the control truly works.

OWASP Course: Guidelines and Standards for Web Application Security

Module 1: Introduction to OWASP

Module 2: Main OWASP Projects

Module 3: OWASP Top Ten 2021 in Depth

Module 4: OWASP ASVS (Application Security Verification Standard)

Module 5: OWASP SAMM (Software Assurance Maturity Model)

Module 6: OWASP ZAP (Zed Attack Proxy)

Module 7: Best Practices and Recommendations

Module 8: Practical Exercises and Case Studies

Module 9: Assessment and Certification

© Copyright 2026. All rights reserved