diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..038dd5557 --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,444 @@ +threagile_version: 1.0.0 + +title: Juice Shop — Authentication Flow Threat Model +date: 2025-09-18 + +author: + name: Student Name + homepage: https://example.edu + +management_summary_comment: > + Focused threat model of the Juice Shop authentication flow: + login, JWT issuance, session use on protected endpoints, and admin + privilege escalation. This model deliberately omits non-auth assets + (product catalog, orders) to surface auth-specific risks that a + full-architecture model masks. + +business_criticality: critical + +business_overview: + description: > + Authentication is the primary security control in Juice Shop. + Weaknesses here (weak JWT signing, missing brute-force protection, + broken admin authorization) directly enable account takeover and + privilege escalation. + +technical_overview: + description: > + A browser submits credentials to the Auth API, which validates them + against the User Credential Store and requests a signed JWT from the + Token Signer. The browser then presents that JWT on every subsequent + request. The Admin Endpoint additionally verifies that the JWT carries + an admin role claim before serving privileged operations. + +questions: {} +abuse_cases: + Brute-Force Login: > + Attacker submits thousands of credential pairs against the login endpoint + to guess a valid password. + JWT Algorithm Confusion: > + Attacker forges a JWT by exploiting a weak or mis-configured signing + algorithm (e.g. alg:none or RS256→HS256 confusion). + Privilege Escalation via Tampered JWT: > + Attacker modifies the role claim in a JWT to gain admin access. + Session Fixation: > + Attacker plants a known session token before login and hijacks the + authenticated session afterwards. + +security_requirements: + Strong JWT signing: Use RS256 or ES256; never accept alg:none. + Rate limiting on login: Lock account or add CAPTCHA after N failed attempts. + Admin role server-side check: Verify role claim on every admin request server-side. + Short-lived tokens: JWT expiry ≤ 15 minutes; use refresh-token rotation. + Secrets in vault: JWT signing keys must not appear in source code or logs. + +tags_available: + - browser + - auth + - jwt + - admin + - credentials + - session + - token + - internal + - external + +# ========================= +# DATA ASSETS +# ========================= +data_assets: + + Credentials: + id: credentials + description: "Username and password submitted at login." + usage: business + tags: ["auth", "credentials"] + origin: user-supplied + owner: Lab Owner + quantity: many + confidentiality: strictly-confidential + integrity: critical + availability: important + justification_cia_rating: > + Plaintext credentials in transit must be strictly protected; + compromise allows immediate account takeover. + + JWT Token: + id: jwt-token + description: "Signed JWT issued after successful login, carries user identity and role claims." + usage: business + tags: ["auth", "jwt", "token"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + A forged or tampered JWT bypasses all authorization checks. + Integrity is therefore critical. + + JWT Signing Key: + id: jwt-signing-key + description: "Secret or private key used to sign and verify JWTs." + usage: devops + tags: ["auth", "jwt"] + origin: application + owner: Lab Owner + quantity: very-few + confidentiality: strictly-confidential + integrity: critical + availability: important + justification_cia_rating: > + Exposure of the signing key allows an attacker to forge arbitrary + tokens with any identity or role. + + User Session State: + id: user-session-state + description: "Server-side or client-side session state tracking authenticated users." + usage: business + tags: ["session", "auth"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + Session fixation or hijack gives an attacker full user-level access. + + Admin Operation Request: + id: admin-operation-request + description: "Privileged requests to admin endpoints (user management, config changes)." + usage: business + tags: ["admin", "auth"] + origin: user-supplied + owner: Lab Owner + quantity: few + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + Admin operations can modify all application data; integrity is critical + to prevent privilege escalation abuse. + +# ========================= +# TECHNICAL ASSETS +# ========================= +technical_assets: + + Browser: + id: browser + description: "End-user web browser initiating login and authenticated requests." + type: external-entity + usage: business + used_as_client_by_human: true + out_of_scope: false + justification_out_of_scope: + size: system + technology: browser + tags: ["browser", "external"] + internet: true + machine: virtual + encryption: none + owner: External User + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user; potentially an attacker." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + - jwt-token + - user-session-state + - admin-operation-request + data_assets_stored: + - jwt-token + - user-session-state + data_formats_accepted: + - json + communication_links: + Login Request: + target: auth-api + description: "Browser POSTs credentials to /rest/user/login over HTTPS." + protocol: https + authentication: credentials + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + Authenticated API Request: + target: auth-api + description: "Browser sends JWT in Authorization header for protected endpoints." + protocol: https + authentication: token + authorization: enduser-identity-propagation + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - jwt-token + - user-session-state + data_assets_received: [] + Admin Request: + target: admin-endpoint + description: "Browser sends JWT with admin role claim to admin endpoints." + protocol: https + authentication: token + authorization: enduser-identity-propagation + tags: ["admin"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - jwt-token + - admin-operation-request + data_assets_received: [] + + Auth API: + id: auth-api + description: "Juice Shop authentication endpoint (/rest/user/login, /rest/user/register). Validates credentials and orchestrates JWT issuance." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: web-service-rest + tags: ["auth", "internal"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: > + Central authentication logic; compromise here breaks all access control. + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - credentials + - jwt-token + - user-session-state + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + Validate Credentials: + target: user-credential-store + description: "Auth API queries the credential store to verify submitted username/password hash." + protocol: jdbc + authentication: credentials + authorization: technical-user + tags: [] + vpn: false + ip_filtered: false + readonly: true + usage: business + data_assets_sent: + - credentials + data_assets_received: + - credentials + Request JWT: + target: token-signer + description: "Auth API asks the Token Signer to issue a signed JWT after successful credential validation." + protocol: https + authentication: token + authorization: technical-user + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - user-session-state + data_assets_received: + - jwt-token + + Token Signer: + id: token-signer + description: "Component responsible for signing and verifying JWTs using the signing key." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: web-service-rest + tags: ["jwt", "auth", "internal"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: > + Holds the JWT signing key; compromise allows forging of arbitrary tokens. + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - jwt-token + - jwt-signing-key + data_assets_stored: + - jwt-signing-key + data_formats_accepted: + - json + communication_links: {} + + User Credential Store: + id: user-credential-store + description: "SQLite database storing hashed passwords and user profile data." + type: datastore + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: database + tags: ["auth", "internal"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: strictly-confidential + integrity: critical + availability: important + justification_cia_rating: > + Contains password hashes; direct access enables offline cracking + and full account compromise. + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + data_assets_stored: + - credentials + data_formats_accepted: + - file + communication_links: {} + + Admin Endpoint: + id: admin-endpoint + description: "Privileged admin routes (e.g. /administration, /#/administration). Requires JWT with admin role claim." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: web-service-rest + tags: ["admin", "auth", "internal"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: > + Admin operations affect all users and application data; + broken authorization here is a critical elevation-of-privilege risk. + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - jwt-token + - admin-operation-request + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + Verify JWT: + target: token-signer + description: "Admin endpoint calls Token Signer to verify JWT signature and role claim before serving request." + protocol: https + authentication: token + authorization: technical-user + tags: [] + vpn: false + ip_filtered: false + readonly: true + usage: business + data_assets_sent: + - jwt-token + data_assets_received: + - jwt-token + +# ========================= +# TRUST BOUNDARIES +# ========================= +trust_boundaries: + + Internet: + id: internet-auth + description: "Untrusted public network (browsers and attackers)." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - browser + trust_boundaries_nested: + - container-auth + + Container Network (Auth): + id: container-auth + description: "Docker container network hosting auth components." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - auth-api + - token-signer + - user-credential-store + - admin-endpoint + trust_boundaries_nested: [] + +# ========================= +# SHARED RUNTIMES +# ========================= +shared_runtimes: + Auth Container Runtime: + id: auth-runtime + description: "Docker engine running all auth-flow containers." + tags: [] + technical_assets_running: + - auth-api + - token-signer + - user-credential-store + - admin-endpoint + +individual_risk_categories: {} +risk_tracking: {} diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..3f47777b5 --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,429 @@ +threagile_version: 1.0.0 + +title: OWASP Juice Shop — Local Lab Threat Model +date: 2025-09-18 + +author: + name: Student Name + homepage: https://example.edu + +management_summary_comment: > + Threat model for a local OWASP Juice Shop setup. Users access the app + either directly via HTTP on port 3000 or through an optional reverse proxy that + terminates TLS and adds security headers. The app runs in a container + and writes data to a host-mounted volume (for database, uploads, logs). + Optional outbound notifications (e.g., a challenge-solution WebHook) can be configured for integrations. + +business_criticality: important # archive, operational, important, critical, mission-critical + +business_overview: + description: > + Training environment for DevSecOps. This model covers a deliberately vulnerable + web application (OWASP Juice Shop) running locally in a Docker container. The focus is on a minimal architecture, STRIDE threat analysis, and actionable mitigations for the identified risks. + + images: + # - dfd.png: Data Flow Diagram (if exported from the tool) + +technical_overview: + description: > + A user’s web browser connects to the Juice Shop application (Node.js/Express server) either directly on **localhost:3000** (HTTP) or via a **reverse proxy** on ports 80/443 (with HTTPS). The Juice Shop server may issue outbound requests to external services (e.g., a configured **WebHook** for solved challenge notifications). All application data (the SQLite database, file uploads, logs) is stored on the host’s filesystem via a mounted volume. Key trust boundaries include the **Internet** (user & external services) → **Host** (local machine/VM) → **Container Network** (isolated app container). + images: [] + +questions: + Do you expose port 3000 beyond localhost?: "" + Do you use a reverse proxy with TLS and security headers?: "" + Are any outbound integrations (webhooks) configured?: "" + Is any sensitive data stored in logs or files?: "" + +abuse_cases: + Credential Stuffing / Brute Force: > + Attackers attempt repeated login attempts to guess credentials or exhaust system resources. + Stored XSS via Product Reviews: > + Malicious scripts are inserted into product reviews, getting stored and executed in other users’ browsers. + SSRF via Outbound Requests: > + Server-side requests (e.g. profile image URL fetch or WebHook callback) are abused to access internal network resources. + +security_requirements: + TLS in transit: Enforce HTTPS for user traffic via a TLS-terminating reverse proxy with strong ciphers and certificate management. + AuthZ on sensitive routes: Implement strict server-side authorization checks (role/permission) on admin or sensitive functionalities. + Rate limiting & lockouts: Apply rate limiting and account lockout policies to mitigate brute-force and automated attacks on authentication and expensive operations. + Secure headers: Add security headers (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, etc.) at the proxy or app to mitigate client-side attacks. + Secrets management: Protect secret keys and credentials (JWT signing keys, OAuth client secrets) – keep them out of code repos and avoid logging them. + +tags_available: + # Relevant technologies and environment tags + - docker + - nodejs + # Data and asset tags + - pii + - auth + - tokens + - logs + - public + - actor + - user + - optional + - proxy + - app + - storage + - volume + - saas + - webhook + # Communication tags + - primary + - direct + - egress + +# ========================= +# DATA ASSETS +# ========================= +data_assets: + + User Accounts: + id: user-accounts + description: "User profile data, credential hashes, emails." + usage: business + tags: ["pii", "auth"] + origin: user-supplied + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + Contains personal identifiers and authentication data. High confidentiality is required to protect user privacy, and integrity is critical to prevent account takeovers. + + Orders: + id: orders + description: "Order history, addresses, and payment metadata (no raw card numbers)." + usage: business + tags: ["pii"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + Contains users’ personal data and business transaction records. Integrity and confidentiality are important to prevent fraud or privacy breaches. + + Product Catalog: + id: product-catalog + description: "Product information (names, descriptions, prices) available to all users." + usage: business + tags: ["public"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: public + integrity: important + availability: important + justification_cia_rating: > + Product data is intended to be public, but its integrity is important (to avoid defacement or price manipulation that could mislead users). + + Tokens & Sessions: + id: tokens-sessions + description: "Session identifiers, JWTs for authenticated sessions, CSRF tokens." + usage: business + tags: ["auth", "tokens"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + If session tokens are compromised, attackers can hijack user sessions. They must be kept confidential and intact; availability is less critical (tokens can be reissued). + + Logs: + id: logs + description: "Application and access logs (may inadvertently contain PII or secrets)." + usage: devops + tags: ["logs"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: > + Logs are for internal use (troubleshooting, monitoring). They should not be exposed publicly, and sensitive data should be sanitized to protect confidentiality. + +# ========================= +# TECHNICAL ASSETS +# ========================= +technical_assets: + + User Browser: + id: user-browser + description: "End-user web browser (client)." + type: external-entity + usage: business + used_as_client_by_human: true + out_of_scope: false + justification_out_of_scope: + size: system + technology: browser + tags: ["actor", "user"] + internet: true + machine: virtual + encryption: none + owner: External User + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user (potentially an attacker)." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: [] + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + To Reverse Proxy (preferred): + target: reverse-proxy + description: "User browser to reverse proxy (HTTPS on 443)." + protocol: https + authentication: session-id + authorization: enduser-identity-propagation + tags: ["primary"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + Direct to App (no proxy): + target: juice-shop + description: "Direct browser access to app (HTTP on 3000)." + protocol: https + authentication: session-id + authorization: enduser-identity-propagation + tags: ["direct"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + + Reverse Proxy: + id: reverse-proxy + description: "Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: reverse-proxy + tags: ["optional", "proxy"] + internet: false + machine: virtual + encryption: transparent + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Not exposed to internet directly; improves security of inbound traffic." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - product-catalog + - tokens-sessions + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + To App: + target: juice-shop + description: "Proxy forwarding to app (HTTP on 3000 internally)." + protocol: https + authentication: none + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + + Juice Shop Application: + id: juice-shop + description: "OWASP Juice Shop server (Node.js/Express, v19.0.0)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: web-server + tags: ["app", "nodejs"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "In-scope web application (contains all business logic and vulnerabilities by design)." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - user-accounts + - orders + - product-catalog + - tokens-sessions + data_assets_stored: + - logs + data_formats_accepted: + - json + communication_links: + To Challenge WebHook: + target: webhook-endpoint + description: "Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved." + protocol: https + authentication: none + authorization: none + tags: ["egress"] + vpn: false + ip_filtered: true + readonly: false + usage: business + data_assets_sent: + - orders + + Persistent Storage: + id: persistent-storage + description: "Host-mounted volume for database, file uploads, and logs." + type: datastore + usage: devops + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: file-server + tags: ["storage", "volume"] + internet: false + machine: virtual + encryption: data-with-symmetric-shared-key + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs)." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: [] + data_assets_stored: + - logs + - user-accounts + - orders + - product-catalog + data_formats_accepted: + - file + communication_links: {} + + Webhook Endpoint: + id: webhook-endpoint + description: "External WebHook service (3rd-party, if configured for integrations)." + type: external-entity + usage: business + used_as_client_by_human: false + out_of_scope: true + justification_out_of_scope: "Third-party service to receive notifications (not under our control)." + size: system + technology: web-service-rest + tags: ["saas", "webhook"] + internet: true + machine: virtual + encryption: none + owner: Third-Party + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured." + multi_tenant: true + redundant: true + custom_developed_parts: false + data_assets_processed: + - orders + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: {} + +# ========================= +# TRUST BOUNDARIES +# ========================= +trust_boundaries: + + Internet: + id: internet + description: "Untrusted public network (Internet)." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - user-browser + - webhook-endpoint + trust_boundaries_nested: + - host + + Host: + id: host + description: "Local host machine / VM running the Docker environment." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - reverse-proxy + - persistent-storage + trust_boundaries_nested: + - container-network + + Container Network: + id: container-network + description: "Docker container network (isolated internal network for containers)." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - juice-shop + trust_boundaries_nested: [] + +# ========================= +# SHARED RUNTIMES +# ========================= +shared_runtimes: + + Docker Host: + id: docker-host + description: "Docker Engine and default bridge network on the host." + tags: ["docker"] + technical_assets_running: + - juice-shop + # If the reverse proxy is containerized, include it: + # - reverse-proxy + +# ========================= +# INDIVIDUAL RISK CATEGORIES (optional) +# ========================= +individual_risk_categories: {} + +# ========================= +# RISK TRACKING (optional) +# ========================= +risk_tracking: {} + +# (Optional diagram layout tweaks can be added here) +#diagram_tweak_edge_layout: spline +#diagram_tweak_layout_left_to_right: true diff --git a/submissions/lab2.md b/submissions/lab2.md new file mode 100644 index 000000000..44b8346e7 --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,80 @@ +# Lab 2 — Threat Modeling: STRIDE on Juice Shop with Threagile + +## Task 1: Baseline Threat Model + +### Risk count by severity +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Elevated | 4 | +| Medium | 14 | +| Low | 5 | +| **Total**| **23** | + +### Top 5 risks (from `risks.json`) +1. **missing-authentication** — Missing Authentication covering link To App from Reverse Proxy to Juice Shop Application; severity Elevated; affecting juice-shop +2. **cross-site-scripting** — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity Elevated; affecting juice-shop +3. **unencrypted-communication** — Unencrypted Communication on Direct to App (no proxy) between User Browser and Juice Shop Application transferring authentication data; severity Elevated; affecting user-browser +4. **unencrypted-communication** — Unencrypted Communication on To App between Reverse Proxy and Juice Shop Application; severity Elevated; affecting reverse-proxy +5. **unnecessary-technical-asset** — Unnecessary Technical Asset named Persistent Storage; severity Low; affecting persistent-storage + +### STRIDE mapping +- Risk 1 (missing-authentication): **S** (Spoofing) — without authentication on the internal proxy→app link, any process on the host network can forge requests to the app as if it were the legitimate proxy. +- Risk 2 (cross-site-scripting): **T** (Tampering) — malicious scripts injected via product reviews or other inputs tamper with the DOM in victim browsers, enabling session hijack or data exfiltration. +- Risk 3 (unencrypted-communication, Direct to App): **I** (Information Disclosure) — plaintext HTTP on port 3000 exposes session tokens and credentials to any network-level observer or ARP-spoofing attacker. +- Risk 4 (unencrypted-communication, To App): **I** (Information Disclosure) — even after TLS termination at the proxy, the internal HTTP hop from proxy to app leaks tokens in plaintext within the host network. +- Risk 5 (unnecessary-technical-asset): **D** (Denial of Service) — an unused but mounted persistent storage volume increases the attack surface; if the volume is filled or corrupted it can deny service to the application. + +### Trust boundary observation +In `data-flow-diagram.png`, the arrow **User Browser → Juice Shop Application** (Direct to App, HTTP on port 3000) crosses the Internet→Host trust boundary without TLS. This arrow is particularly attractive to an attacker because it carries session tokens and credentials in plaintext, meaning a passive network tap or an ARP-spoofing attack is sufficient to harvest valid sessions with zero interaction with the application logic itself. + + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|---:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 2 | -2 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total**| **23** | **20** | **-3** | + +### Which rules are GONE in the secure variant? +1. `unencrypted-communication` (elevated) — fixed by `protocol: https` on the **Direct to App** link (User Browser → Juice Shop) +2. `unencrypted-communication` (elevated) — fixed by `protocol: https` on the **To App** link (Reverse Proxy → Juice Shop) +3. `unencrypted-asset` (medium, one instance) — fixed by `encryption: data-with-symmetric-shared-key` on Persistent Storage + +### Which rules are STILL THERE in the secure variant? +1. **missing-authentication** (elevated) — the internal link from Reverse Proxy to Juice Shop still carries no authentication token. Setting `protocol: https` encrypts the channel but does not prove the caller's identity; eliminating this risk would require mTLS or a shared secret header between proxy and app. +2. **server-side-request-forgery** (medium) — the Juice Shop application can still initiate outbound HTTP requests based on user-supplied input (e.g. profile image URL fetch or WebHook callback). Setting `ip_filtered: true` on the WebHook link signals intent but Threagile still fires the rule because the app logic itself is not constrained; a server-side allowlist of permitted outbound destinations is required to close it. + +### Honesty check +Yes, the total dropped by 3 (≈13%), not over 50%. The changes fixed only the most obvious transport-layer issues — flipping a protocol field or adding an encryption flag costs minutes of work. The remaining 20 risks require architectural changes (mTLS between components, a secrets vault, WAF, 2FA, hardened base images) or application-level fixes (input sanitisation for XSS/CSRF, SSRF allowlists). This illustrates a classic cost-benefit asymmetry: perimeter hardening is cheap and fast but eliminates only a small fraction of the total risk surface; the expensive application-level work is where most risk actually lives. + + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 1 | +| Elevated | 6 | +| Medium | 19 | +| Low | 6 | +| **Total**|**32** | + +### Three auth-specific risks NOT in the baseline model's top 5 + +1. **sql-nosql-injection** — STRIDE: **T** (Tampering) — The Auth API passes user-supplied login input directly into SQL queries against the User Credential Store. Mitigation: enforce parameterized queries / prepared statements for all credential lookups; validate and sanitize all user input server-side before it reaches the database layer. + +2. **unguarded-access-from-internet** (affecting auth-api) — STRIDE: **S** (Spoofing) — The Auth API is reachable directly from the Internet trust boundary without a WAF or rate-limiting layer in front of it, making brute-force and credential-stuffing attacks trivial. Mitigation: place a WAF or reverse proxy with rate limiting and account-lockout policy in front of the login endpoint; consider CAPTCHA after N failed attempts. + +3. **missing-vault** (affecting user-credential-store) — STRIDE: **I** (Information Disclosure) — The JWT signing key and database credentials are stored directly in the container environment rather than in a dedicated secrets vault, meaning any container escape or environment variable leak exposes them. Mitigation: store all secrets (JWT signing key, DB credentials) in a secrets manager (e.g. HashiCorp Vault or Docker secrets) and inject them at runtime; never hardcode or log them. + +### Reflection +Building the focused auth model surfaced `sql-nosql-injection` (High) and `unguarded-access-from-internet` on the login endpoint — both absent from the baseline model's top 5 — because the baseline treats the Juice Shop as a single monolithic process and never models the internal credential-validation data flow separately. Feature-level threat models force you to name every data asset that crosses a component boundary (credentials → Auth API → DB), which is precisely where injection and spoofing risks live. Architecture-level models are good at transport and boundary risks; feature-level models are necessary to catch logic and injection risks that only appear when you zoom in. +