|
| 1 | +# Lab 5 — Submission |
| 2 | + |
| 3 | +## Task 1: DAST with OWASP ZAP |
| 4 | + |
| 5 | +### Baseline (unauthenticated) scan |
| 6 | +- Duration: 1.5 minutes |
| 7 | +- Total alerts: 10 |
| 8 | + |
| 9 | +| Severity | Count | |
| 10 | +|----------|------:| |
| 11 | +| High | 0 | |
| 12 | +| Medium | 2 | |
| 13 | +| Low | 5 | |
| 14 | +| Informational | 3 | |
| 15 | + |
| 16 | +### Authenticated full scan |
| 17 | +- Duration: 4.5 minutes |
| 18 | +- Total alerts: 12 |
| 19 | + |
| 20 | +| Severity | Count | |
| 21 | +|----------|------:| |
| 22 | +| High | 1 | |
| 23 | +| Medium | 4 | |
| 24 | +| Low | 3 | |
| 25 | +| Informational | 4 | |
| 26 | + |
| 27 | +### The "10–20× more" claim (Lecture 5 slide 11) |
| 28 | +- Ratio (auth alerts / baseline alerts): 1.2× |
| 29 | +- Did your run match the lecture's ratio? |
| 30 | + No, my run showed a ratio of 1.2× for unique alert *types*. The lecture's claim likely refers to the sheer volume of vulnerable *instances* (URLs/parameters), as an authenticated crawler accesses exponentially more pages behind the login. Our script only counted unique risk categories. |
| 31 | +- Pick **two specific alerts** that only the authenticated scan found. For each: |
| 32 | + 1. **SQL Injection (High)** |
| 33 | + - Why was it unreachable to the unauthenticated scan? The vulnerable endpoint or parameter is located behind the login barrier, so the baseline crawler couldn't reach the page to inject the payload. |
| 34 | + 2. **Session ID in URL Rewrite (Medium)** |
| 35 | + - Why was it unreachable to the unauthenticated scan? This vulnerability relies on a user session being actively established; since the baseline scan does not log in, it cannot trigger or observe session management flaws. |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | +## Task 2: SAST with Semgrep |
| 42 | + |
| 43 | +### Semgrep severity breakdown |
| 44 | +| Severity | Count | |
| 45 | +|----------|------:| |
| 46 | +| ERROR | 12 | |
| 47 | +| WARNING | 10 | |
| 48 | +| INFO | 0 | |
| 49 | +| **Total** | 22 | |
| 50 | + |
| 51 | +### Top 10 rules by frequency |
| 52 | +| Rule ID | Count | OWASP category | |
| 53 | +|---------|------:|----------------| |
| 54 | +| `javascript.sequelize.security.audit.sequelize-injection-express.express-sequelize-injection` | 6 | A03 | |
| 55 | +| `yaml.github-actions.security.run-shell-injection.run-shell-injection` | 5 | A03 | |
| 56 | +| `javascript.express.security.audit.express-res-sendfile.express-res-sendfile` | 4 | A01 | |
| 57 | +| `javascript.express.security.audit.express-check-directory-listing.express-check-directory-listing` | 4 | A01 | |
| 58 | +| `javascript.jsonwebtoken.security.jwt-hardcode.hardcoded-jwt-secret` | 1 | A02 | |
| 59 | +| `javascript.express.security.audit.express-open-redirect.express-open-redirect` | 1 | A01 | |
| 60 | +| `javascript.lang.security.audit.code-string-concat.code-string-concat` | 1 | A03 | |
| 61 | + |
| 62 | +### Triage shortcut (Lecture 5 slide 8) |
| 63 | +Looking at the top 10 — which **one rule** would you fix first if you had time for only one? |
| 64 | +I would fix `express-sequelize-injection` first. It has the highest frequency among the vulnerabilities found and represents a severe flaw (SQL Injection - A03), meaning fixing the parameter binding at the ORM level here would quickly eliminate a large cluster of critical vulnerabilities. |
| 65 | + |
| 66 | +### False-positive sample |
| 67 | +File path: `data/static/codefixes/unionSqlInjectionChallenge_1.ts` |
| 68 | +Rule: `express-sequelize-injection` |
| 69 | +Reason: This file is just a static fixture containing code snippets used to display code fixes in the UI; it's not actually executed by the backend, making this finding a false positive. |
| 70 | + |
| 71 | + |
| 72 | + |
| 73 | + |
| 74 | + |
| 75 | + |
| 76 | + ## Bonus: SAST/DAST Correlation |
| 77 | + |
| 78 | +### Correlation table |
| 79 | +| # | OWASP cat | ZAP alert | ZAP URI | Semgrep rule | Semgrep file:line | Confidence | |
| 80 | +|---|-----------|-----------|---------|--------------|-------------------|------------| |
| 81 | +| 1 | A03 Injection | SQL Injection | `/rest/products/search?q=...` | `express-sequelize-injection` | `routes/search.ts:23` | High (both agree) | |
| 82 | +| 2 | A03 Injection | SQL Injection | `/rest/user/login` (email) | `express-sequelize-injection` | `routes/login.ts:34` | High (both agree) | |
| 83 | + |
| 84 | +### Strongest correlation deep-dive |
| 85 | +**1. Vulnerable code (from `routes/search.ts:23`)** |
| 86 | +```typescript |
| 87 | +models.sequelize.query(`SELECT * FROM Products WHERE ((name LIKE '%${criteria}%' OR description LIKE '%${criteria}%') AND deletedAt IS NULL) ORDER BY name`) |
| 88 | +``` |
| 89 | + |
| 90 | +**2. Working payload (from ZAP report)** |
| 91 | +``` |
| 92 | +URL: http://juice-shop:3000/rest/products/search?q=%27%28 |
| 93 | +Parameter: q |
| 94 | +Attack: '( |
| 95 | +``` |
| 96 | + |
| 97 | +**3. The fix** |
| 98 | +Use parameterized queries (bind variables) instead of string interpolation: |
| 99 | +```typescript |
| 100 | +models.sequelize.query( |
| 101 | + 'SELECT * FROM Products WHERE ((name LIKE :criteria OR description LIKE :criteria) AND deletedAt IS NULL) ORDER BY name', |
| 102 | + { replacements: { criteria: `%${criteria}%` } } |
| 103 | +) |
| 104 | +``` |
| 105 | + |
| 106 | +**4. Why both tools caught it** |
| 107 | +Semgrep caught it because the code directly interpolates a user-controlled variable (`criteria` from `req.query.q`) into a raw SQL query string inside the `sequelize.query` call—a classic static pattern. ZAP caught it because during its active crawl it injected SQL metacharacters like `'(` into the `q` parameter and observed a database syntax error or unexpected behavior in the response. |
| 108 | + |
| 109 | +### Reflection (2-3 sentences) |
| 110 | +Lecture 5 slide 15 calls this "the highest-confidence finding type." In a real PR review, I would want the **SAST finding** first. SAST points exactly to the file and line number (`routes/search.ts:23`), which makes it trivial for a developer to implement a fix immediately. The DAST evidence is then incredibly valuable to prove the exploitability of the finding and to verify that the fix actually resolved the issue at runtime. |
0 commit comments