# STRIDE Threat Model: Chapter 3 Flask Application

## System Description

A deliberately vulnerable web application consisting of three elements and two trust boundaries:

| Element | DFD Type | Description |
|---------|----------|-------------|
| Browser | External entity | Untrusted client -- anything sent here is attacker-controlled |
| Flask app | Process | Python web application running on port 5000 |
| SQLite DB | Data store | File-backed relational database at /data/users.db |

Trust boundaries:
- **TB1**: Browser <-> Flask (untrusted input enters here -- the primary attack surface)
- **TB2**: Flask <-> SQLite (privilege boundary; Flask runs as a non-root process)

## Data Flows

```
[Browser] ---HTTP POST /login (username, password)---> [Flask App]
[Flask App] ---SQL query (string-concatenated)-------> [SQLite DB]
[SQLite DB] ---row result---------------------------- > [Flask App]
[Flask App] ---HTTP response (rendered template)-----> [Browser]

[Browser] ---HTTP GET /greet?name=<input>-----------> [Flask App]
[Flask App] ---render_template_string(user input)---> [Browser]
```

## STRIDE-per-Element Analysis

Fill in the "Evidence / Finding" column as you walk the application.

| # | Element | STRIDE Category | Threat | Evidence / Finding | Mitigation (from Ch 3) |
|---|---------|-----------------|--------|--------------------|------------------------|
| 1 | Browser -> Flask (TB1) | **S**poofing | User identity spoofed via weak session or stolen cookie | HttpOnly/Secure flags absent on session cookie | Set HttpOnly + Secure on session cookie; use flask-login |
| 2 | Flask (login endpoint) | **T**ampering | SQL injection allows attacker to modify query logic | String-concatenated query: `WHERE name='...'` | Parameterised queries (sqlite3 `?` placeholders) |
| 3 | Flask (login endpoint) | **T**ampering | SSTI in /greet endpoint allows template modification | `render_template_string(f"Hello {name}")` | Never render user input as a template; use static templates |
| 4 | Flask (login endpoint) | **R**epudiation | No authentication event logging | No log.info/warning on login success or failure | Log auth events with timestamp and username (server-side only) |
| 5 | Flask -> Browser | **I**nformation Disclosure | Stack trace + raw SQL exposed on exception | `return f"ERROR: {e}\nQuery: {query}"` on 500 | Generic error page; log detail server-side only |
| 6 | SQLite DB | **I**nformation Disclosure | SQL injection exfiltrates entire users table | `' OR '1'='1` bypasses WHERE clause | Parameterised queries |
| 7 | Flask (all endpoints) | **D**enial of Service | Unbounded query / no rate limit | No pagination, no request limiting | Add query LIMIT; add flask-limiter rate limiting |
| 8 | Flask (greet endpoint) | **E**levation of Privilege | SSTI can escalate to RCE (template sandbox escape) | `{{ config }}`, `{{ ''.__class__...}}` patterns | Disable user-controlled template rendering entirely |
| 9 | Flask (password store) | **S**poofing | Bare MD5 hash crackable in seconds | `hashlib.md5(password.encode()).hexdigest()` | Replace with bcrypt / scrypt / Argon2 |

## Threats Table (Compact Deliverable)

| Element | STRIDE | Threat | Mitigation | Priority |
|---------|--------|--------|------------|----------|
| Login form | T, I | SQL injection (whole table leak) | Parameterised queries | High |
| Greet endpoint | T, E | SSTI -> RCE | Static templates, no user input in template string | Critical |
| Password store | S | Bare MD5, offline crackable | Argon2id with salt | High |
| Error handler | I | Stack trace + raw query leaked | Generic error page | Medium |
| Auth flow | R | No login event logging | Structured auth logging | Medium |
| All endpoints | D | No rate limiting | flask-limiter | Medium |

## Instructions for Lab 7.8

1. Start the Flask app: `docker compose up -d flask-vuln`
2. Open http://localhost:5000 in a browser.
3. Work through each row of the STRIDE table above, reproducing the evidence:
   - Try `' OR '1'='1` as username with any password in the login form.
   - Try `http://localhost:5000/greet?name={{ 7*7 }}` to confirm SSTI (you should see 49).
   - Try `http://localhost:5000/login` with a username that triggers an error (e.g., a single quote).
4. For each finding, note which STRIDE category applies and confirm the mitigation would close it.
5. Produce your own threats table as the lab deliverable.

**Authorisation note:** Only test against the lab container on localhost.
