diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..a667fbaf7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +## Goal +Lab 1 submission: Juice Shop deployed, triage report completed, and CI smoke test added. + +## Changes +- Added `submissions/lab1.md` with full triage report. +- Created `.github/PULL_REQUEST_TEMPLATE.md`. +- Added `.github/workflows/lab1-smoke.yml` for CI testing. + +## Testing +- Verified Juice Shop is running locally on port 3000 (HTTP 200). +- GitHub Actions workflow ran successfully and passed the smoke test. + +## Artifacts & Screenshots +- See `submissions/lab1.md` for the full report. +- Actions run: [link] + +--- +### Checklist +- [x] Title is clear (`feat(lab1): juice shop deploy + PR template + triage report` style) +- [x] No secrets/large temp files committed +- [x] Submission file at `submissions/lab1.md` exists + +--- +### Task Checklist +- [x] Task 1 done — Juice Shop deployed, triage report in submissions/lab1.md +- [x] Task 2 done — .github/PULL_REQUEST_TEMPLATE.md created +- [x] Task 3 done — GitHub stars + follows complete +- [x] Bonus done — lab1-smoke.yml runs green on this PR diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..906760505 --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,246 @@ +threagile_version: 1.0.0 + +title: Juice Shop Auth Flow +date: 2026-06-13 + +author: + name: Gainutdinova Aliya + homepage: https://github.com/alileeeek + +management_summary_comment: > + Focused threat model for Juice Shop authentication flow. + +business_criticality: important + +data_assets: + + credentials: + id: credentials + description: "User credentials (username + password)" + usage: business + quantity: many + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "Credentials must be protected" + + jwt-token: + id: jwt-token + description: "JWT token issued after authentication" + usage: business + quantity: many + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "JWT tokens grant access" + + session-state: + id: session-state + description: "User session state" + usage: business + quantity: many + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "Session state must be protected" + + admin-requests: + id: admin-requests + description: "Admin operation requests" + usage: business + quantity: few + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "Admin operations are highly sensitive" + +technical_assets: + + browser: + id: browser + description: "User's web browser" + type: external-entity + usage: business + used_as_client_by_human: true + out_of_scope: false + size: system + technology: browser + internet: true + machine: virtual + encryption: none + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user" + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + browser-to-auth-api: + target: auth-api + description: "User submits credentials for login/register" + protocol: https + authentication: none + authorization: enduser-identity-propagation + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + browser-to-admin: + target: admin-endpoint + description: "Admin requests requiring JWT with admin role" + protocol: https + authentication: token + authorization: enduser-identity-propagation + usage: business + data_assets_sent: + - jwt-token + - admin-requests + + auth-api: + id: auth-api + description: "Authentication API endpoint" + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + internet: false + machine: container + encryption: none + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Auth API handles credentials" + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - credentials + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + auth-api-to-token-signer: + target: token-signer + description: "Request JWT token generation" + protocol: https + authentication: none + authorization: enduser-identity-propagation + usage: business + data_assets_sent: + - credentials + auth-api-to-user-db: + target: user-db + description: "Verify user credentials" + protocol: https + authentication: credentials + authorization: enduser-identity-propagation + usage: business + data_assets_sent: + - credentials + + token-signer: + id: token-signer + description: "JWT token signing component" + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-service-rest + internet: false + machine: container + encryption: none + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Token signer issues JWTs" + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + + user-db: + id: user-db + description: "User credentials database" + type: datastore + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: database + internet: false + machine: container + encryption: none + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Stores user credentials" + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + data_assets_stored: + - credentials + data_formats_accepted: + - json + + admin-endpoint: + id: admin-endpoint + description: "Admin API endpoint" + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + internet: false + machine: container + encryption: none + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Admin operations are sensitive" + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - admin-requests + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + +trust_boundaries: + + internet: + id: internet + description: "Public internet" + type: network-dedicated-hoster + technical_assets_inside: + - browser + + container: + id: container + description: "Docker container running Juice Shop" + type: network-dedicated-hoster + technical_assets_inside: + - auth-api + - token-signer + - user-db + - admin-endpoint diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..b46a0825a --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,430 @@ +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 + +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: [] + +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: + - docker + - nodejs + - pii + - auth + - tokens + - logs + - public + - actor + - user + - optional + - proxy + - app + - storage + - volume + - saas + - webhook + - primary + - direct + - egress + +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: + + 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 + To Database: + target: persistent-storage + description: "Database connection using parameterized queries (prepared statements)" + protocol: https + authentication: credentials + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - user-accounts + - orders + data_assets_received: + - product-catalog + To Logging: + target: persistent-storage + description: "Encrypted log writes to persistent storage" + protocol: https + authentication: none + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: devops + data_assets_sent: + - logs + + 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: + + 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: + + Docker Host: + id: docker-host + description: "Docker Engine and default bridge network on the host." + tags: ["docker"] + technical_assets_running: + - juice-shop + +individual_risk_categories: {} + +risk_tracking: {} \ No newline at end of file diff --git a/submissions/lab2.md b/submissions/lab2.md new file mode 100644 index 000000000..b1f7e533e --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,80 @@ +# Lab 2 — Submission + +## 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** — Direct to App (no proxy); severity elevated; affecting user-browser +2. **unencrypted-communication** — To App (via Reverse Proxy); severity elevated; affecting reverse-proxy +3. **missing-authentication** — To App (via Reverse Proxy); severity elevated; affecting juice-shop +4. **cross-site-scripting** — XSS risk at Juice Shop; severity elevated; affecting juice-shop +5. **unnecessary-data-transfer** — Tokens & Sessions; severity low; affecting user-browser + +### STRIDE mapping +- Risk 1: **I (Information Disclosure)** — Unencrypted HTTP allows attackers to intercept authentication data in transit. +- Risk 2: **I (Information Disclosure)** — Internal traffic between proxy and app is unencrypted, risking data interception. +- Risk 3: **E (Elevation of Privilege)** — Missing authentication on internal links allows unauthorized access to the app. +- Risk 4: **T (Tampering)** — XSS allows attackers to modify page content and steal user data. +- Risk 5: **I (Information Disclosure)** — Sending unnecessary tokens increases the attack surface for data theft. + +### Trust boundary observation +Arrow: User Browser (Internet) -> Juice Shop Application (Container). +Why attractive: It crosses the main trust boundary from the untrusted internet directly to the app without encryption (HTTP), making it the easiest target for Man-in-the-Middle attacks to steal credentials. + + + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 5 | +1 | +| Medium | 14 | 14 | 0 | +| Low | 5 | 5 | 0 | +| **Total** | 23 | 24 | +1 | + +### Which rules are GONE in the secure variant? +1. `unencrypted-communication` (Reverse Proxy to App) — fixed by changing protocol from http to https +2. `insecure-data-storage` (Persistent Storage) — fixed by adding encryption: data-with-symmetric-shared-key +3. `missing-transport-layer-encryption` (WebHook) — already was https, no change needed + +### Which rules are STILL THERE in the secure variant? +1. `missing-authentication` — Still present because we only encrypted communication but didn't add authentication middleware to protect endpoints. The Reverse Proxy to App link still has `authentication: none`. +2. `cross-site-scripting` — XSS vulnerability remains because encrypting transport doesn't fix input validation issues in the application code. This requires code-level changes, not just configuration. + +### Honesty check +Did the total drop more than 50%? No, it actually increased by 1 (23 → 24). +This happened because I added two new communication links (To Database and To Logging) to demonstrate prepared statements and encrypted logging, which introduced new risks. The encryption changes fixed some risks but the new links created others. To truly reduce risks, I would need to add authentication to the new links and ensure all security requirements are declared. This shows that threat modeling is iterative — each change needs to be carefully evaluated to avoid introducing new vulnerabilities while fixing old ones. + + + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Elevated | 3 | +| Medium | 19 | +| Low | 6 | +| **Total** | 28 | + +### Three auth-specific risks (NOT in the baseline model's top 5) +1. **sql-nosql-injection** — STRIDE: T (Tampering) — Mitigation: Use parameterized queries in auth-api when checking credentials against user-db to prevent SQL injection attacks that could bypass authentication. +2. **missing-authentication** (auth-api-to-token-signer) — STRIDE: E (Elevation of Privilege) — Mitigation: Add authentication between auth-api and token-signer to prevent unauthorized components from requesting JWT tokens on behalf of users. +3. **missing-authentication** (browser-to-auth-api) — STRIDE: S (Spoofing) — Mitigation: Implement proper authentication checks on the login endpoint to prevent attackers from impersonating users or brute-forcing credentials without rate limiting. + +### Reflection (2-3 sentences) +Building the focused auth model revealed risks specific to the authentication flow that the baseline architecture model missed, such as SQL injection in the credential verification path and missing authentication between internal auth components. Feature-level threat models provide deeper insights into specific workflows, while architecture-level models give a broader but shallower view. The auth model showed that even with HTTPS encryption, application-level vulnerabilities like SQL injection and missing authentication remain critical attack vectors that require code-level fixes.