From 5446c057df1b444f203fd6d51396409544fe8eff Mon Sep 17 00:00:00 2001 From: Karina Krotova Date: Fri, 12 Jun 2026 23:47:11 +0300 Subject: [PATCH 1/2] feat(lab2): add Threagile threat model analysis --- labs/lab2/threagile-model-secure.yaml | 431 ++++++++++++++++++++++++++ submissions/lab2.md | 112 +++++++ 2 files changed, 543 insertions(+) create mode 100644 labs/lab2/threagile-model-secure.yaml create mode 100644 submissions/lab2.md diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..6f2b47611 --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,431 @@ +threagile_version: 1.0.0 + +title: OWASP Juice Shop 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: false + 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: none + 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..cb802810d --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,112 @@ +\# 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 + + + +1\. \*\*unencrypted-communication\*\* — Unencrypted communication between User Browser and Juice Shop Application; severity: Elevated; affecting asset: User Browser. + +2\. \*\*unencrypted-communication\*\* — Unencrypted communication between Reverse Proxy and Juice Shop Application; severity: Elevated; affecting asset: Reverse Proxy. + +3\. \*\*cross-site-scripting\*\* — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity: Elevated; affecting asset: Juice Shop Application. + +4\. \*\*missing-authentication\*\* — Missing authentication on communication link between Reverse Proxy and Juice Shop Application; severity: Elevated; affecting asset: Juice Shop Application. + +5\. \*\*missing-vault\*\* — Missing secret storage (Vault) for Juice Shop Application; severity: Medium; affecting asset: Juice Shop Application. + + + +\### STRIDE Mapping + + + +\* Risk 1: \*\*I (Information Disclosure)\*\* — Credentials and session information may be intercepted over unencrypted communication. + +\* Risk 2: \*\*I (Information Disclosure)\*\* — Traffic between proxy and application can be observed or modified by an attacker. + +\* Risk 3: \*\*T (Tampering)\*\* — XSS allows attackers to inject and execute malicious code in user browsers. + +\* Risk 4: \*\*S (Spoofing)\*\* — Missing authentication enables unauthorized entities to impersonate trusted components. + +\* Risk 5: \*\*E (Elevation of Privilege)\*\* — Secrets stored without proper vaulting can be abused to gain elevated access. + + + +\### Trust Boundary Observation + + + +One important trust-boundary crossing is the communication link between \*\*User Browser\*\* and \*\*Juice Shop Application\*\* (`user-browser > direct-to-app-no-proxy`). + + + +This communication appears in the top risks because it transfers authentication-related information across a trust boundary. Attackers can target this path using traffic interception, credential theft, or man-in-the-middle techniques when communication is not properly protected. + +## Task 2: Secure Variant & Diff + +### Changes made in the secure variant + +I created `labs/lab2/threagile-model-secure.yaml` from the baseline model and applied the following hardening changes: + +- Changed HTTP communication links to HTTPS. +- Changed unencrypted asset storage to `data-with-symmetric-shared-key`. +- Added a secure-variant note that database access uses parameterized queries / prepared statements. +- Re-generated the Threagile report in `labs/lab2/output-secure`. + +### Risk count comparison + +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 2 | -2 | +| Medium | 14 | 14 | 0 | +| Low | 5 | 5 | 0 | +| **Total** | **23** | **21** | **-2** | + +### Which rules are gone in the secure variant? + +The secure variant reduced the number of Elevated risks from 4 to 2. The main fixed rule category was: + +1. `unencrypted-communication` — fixed by changing HTTP communication links to HTTPS. + +Because this model only had two HTTP communication risks, the total dropped by 2 risks. + +### Which rules are still there in the secure variant? + +1. `cross-site-scripting` — This risk still appears because switching transport from HTTP to HTTPS does not remove browser-side script injection issues. XSS requires input validation, output encoding, and content security controls. + +2. `missing-authentication` — This risk still appears because the secure variant did not add a new authentication mechanism between the reverse proxy and the Juice Shop application. HTTPS protects the channel, but it does not prove that the caller is authorized. + +### Honesty check + +The total risk count did not drop by more than 50%. It dropped from 23 to 21, which shows that HTTPS and encryption are useful but only address a narrow part of the threat model. Fully reducing the remaining risks would require more specific controls such as authentication, input validation, hardening, secret management, and application-level security fixes. + From 696172d308af5fe0f7e7f651124029a6ab966be4 Mon Sep 17 00:00:00 2001 From: Karina Krotova Date: Fri, 12 Jun 2026 23:54:36 +0300 Subject: [PATCH 2/2] docs(lab2): clarify fixed rules in secure variant --- submissions/lab2.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/submissions/lab2.md b/submissions/lab2.md index cb802810d..2f35912fa 100644 --- a/submissions/lab2.md +++ b/submissions/lab2.md @@ -94,12 +94,13 @@ I created `labs/lab2/threagile-model-secure.yaml` from the baseline model and ap ### Which rules are gone in the secure variant? -The secure variant reduced the number of Elevated risks from 4 to 2. The main fixed rule category was: +The secure variant reduced the number of Elevated risks from 4 to 2. The main fixed rule category was `unencrypted-communication`. -1. `unencrypted-communication` — fixed by changing HTTP communication links to HTTPS. - -Because this model only had two HTTP communication risks, the total dropped by 2 risks. +1. `unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop` — fixed by changing the direct user-to-application communication from HTTP to HTTPS. +2. `unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop` — fixed by changing the reverse-proxy-to-application communication from HTTP to HTTPS. +3. `unencrypted-communication` — fixed as a broader rule category by removing plaintext HTTP communication from the model. +Only two concrete risk instances disappeared, so the third item is the fixed rule category rather than a third separate instance. This is a limitation of this model's output: the secure changes removed two Elevated findings, not three distinct risk instances. ### Which rules are still there in the secure variant? 1. `cross-site-scripting` — This risk still appears because switching transport from HTTP to HTTPS does not remove browser-side script injection issues. XSS requires input validation, output encoding, and content security controls.