From 52494d26b89f52f7042cf53abd849f5a2bfda069 Mon Sep 17 00:00:00 2001 From: diffouo44 Date: Wed, 10 Jun 2026 05:23:36 +0300 Subject: [PATCH 1/4] chore(lab2): remove lab1 files so PR contains only lab2 work --- .github/PULL_REQUEST_TEMPLATE.md | 34 ------- .github/workflows/lab1-smoke.yml | 39 -------- labs/submissions/lab1.md | 0 submissions/lab1.md | 152 ------------------------------- 4 files changed, 225 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/workflows/lab1-smoke.yml delete mode 100644 labs/submissions/lab1.md delete mode 100644 submissions/lab1.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index c0c2f6bc8..000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ -# Goal - - - -# Changes - - -- -- - -# Testing - - - -```bash -# commands -``` - -```text -# observed output -``` - -# Artifacts & Screenshots - - -- [submissions/labN.md](../blob/HEAD/submissions/lab1.md) - ---- - -## Checklist - -- [ ] Title is clear (`feat(labN): ` style) -- [ ] No secrets/large temp files committed -- [ ] Submission file at `submissions/labN.md` exists diff --git a/.github/workflows/lab1-smoke.yml b/.github/workflows/lab1-smoke.yml deleted file mode 100644 index fc6348941..000000000 --- a/.github/workflows/lab1-smoke.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Lab1 Smoke Test - -on: - pull_request: - branches: [ main ] - -permissions: - contents: read - -jobs: - smoke: - name: Smoke-test Juice Shop - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Run Juice Shop container - run: | - docker run -d --name juice-shop -p 3000:3000 bkimminich/juice-shop:v20.0.0 - - - name: Wait for Juice Shop to respond - run: | - for i in $(seq 1 30); do - if curl --silent --fail http://localhost:3000/rest/admin/application-version >/dev/null 2>&1; then - echo "juice-shop healthy"; exit 0 - fi - sleep 2 - done - echo "juice-shop did not become healthy"; docker logs juice-shop || true; exit 1 - - - name: Curl homepage - run: | - curl --silent --fail -I http://localhost:3000 | head -n 20 - - - name: Stop container - if: always() - run: | - docker stop juice-shop || true diff --git a/labs/submissions/lab1.md b/labs/submissions/lab1.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/submissions/lab1.md b/submissions/lab1.md deleted file mode 100644 index 6ca8163d9..000000000 --- a/submissions/lab1.md +++ /dev/null @@ -1,152 +0,0 @@ -# Lab 1 — Submission - -## Triage Report: OWASP Juice Shop - -### Scope & Asset -- Asset: OWASP Juice Shop (local lab instance) -- Image: `bkimminich/juice-shop:v20.0.0` -- Image digest: `sha256:99779f57113bd47312e8fe7b264ff402ee41da76ddda7f2fc842a92ad51827ce` (from `docker inspect juice-shop --format '{{.Image}}'`) -- Host OS: Linux (detected by the container runtime) -- Docker version: `Docker version 29.4.0, build 9d7ad9f` - -### Deployment Details -- Run command used: - - ```bash - docker run -d --name juice-shop \ - -p 127.0.0.1:3000:3000 \ - bkimminich/juice-shop:v20.0.0 - ``` -- Access URL: http://127.0.0.1:3000 -- Network exposure: 127.0.0.1 only — container bound to localhost -- Container restart policy: default (`no`) - -### Health Check -- HTTP code on `/`: `200` -API check (first 200 chars of `/api/Products`): - - ```json - {"status":"success","data":[{"id":1,"name":"Apple Juice (1000ml)","description":"The all-time classic.","price":1.99,"deluxePrice":0.99,"image":"apple_juice.jpg","createdAt":"2026-06-10T01:28:01.171Z"... - ``` - -- Product count from `/api/Products`: `46` -- Container uptime (sample): - - ```text - juice-shop Up 5 seconds 127.0.0.1:3000->3000/tcp - ``` - -### Initial Surface Snapshot (from browser exploration) -- Login/Registration visible: Yes — account menu has Login/Register -- Product listing/search present: Yes — products displayed on landing page -- Admin or account area discoverable: Admin endpoints under `/rest/admin/` discovered via API probe -- Client-side errors in DevTools console: None observed during initial load -- Pre-populated local storage / cookies: Local storage contains `challenge_*` keys and UI state - -### Security Headers (Quick Look) -Run: `curl -I http://127.0.0.1:3000 | head -20` - -Example output (trimmed): - -``` -HTTP/1.1 200 OK -Access-Control-Allow-Origin: * -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -Feature-Policy: payment 'self' -X-Recruiting: /#/jobs -Accept-Ranges: bytes -Cache-Control: public, max-age=0 -Last-Modified: Wed, 10 Jun 2026 01:28:02 GMT -ETag: W/"26af-19eaf24c181" -Content-Type: text/html; charset=UTF-8 -Content-Length: 9903 -Vary: Accept-Encoding -Date: Wed, 10 Jun 2026 01:28:41 GMT -Connection: keep-alive -Keep-Alive: timeout=5 -``` - -Missing headers observed: -- `Content-Security-Policy` — missing -- `Strict-Transport-Security` — missing (site served over HTTP) - -### Top 3 Risks Observed (2-3 sentences each) -1. **Missing transport-layer protection** — The application is served over HTTP; sensitive tokens and session data can be exposed. Maps to OWASP Top 10:2025 A03 (Sensitive Data Exposure). - -2. **Exposed admin endpoints** — Admin API surface under `/rest/admin/*` is discoverable and may be improperly protected; maps to A05 (Broken Access Control). - -3. **Sensitive data in client storage** — Local storage contains challenge and state artifacts which could leak secrets if an XSS exists; maps to A06 (Security Misconfiguration / Sensitive Data Exposure). - ---- - -## PR Template Setup - -- File added: `.github/PULL_REQUEST_TEMPLATE.md` -- Sections included: Goal / Changes / Testing / Artifacts & Screenshots -- Checklist included: Title style, No secrets/large files, `submissions/labN.md` present -- Auto-fill verification: To verify, push `feature/lab1` and open a draft PR — the PR description should pre-fill with this template. - -Template (example): - -```markdown -## Goal -One-sentence description of what this PR delivers. - -## Changes -- List files added or modified - -## Testing -- Commands run and observed output - -## Artifacts & Screenshots -- Links to submission files and images - -- [ ] Title uses `feat(labN): ` style -- [ ] No secrets/large temp files committed -- [ ] `submissions/labN.md` present -``` - ---- - -## GitHub Community - -- Starred: DevSecOps-Intro (course repo), simple-container-com/api -- Followed: @Cre-eD, @Naghme98, @pierrepicaud, and three classmates - -Why: Starring helps discovery and signals interest; following instructors and peers enables collaboration and timely updates. - ---- - -## Bonus: CI Smoke Test (notes) - -The smoke-test workflow (`.github/workflows/lab1-smoke.yml`) should: - -- Trigger: `pull_request` on `main` -- Use `ubuntu-latest` runner -- Set `permissions: { contents: read }` at workflow level -- Pull `bkimminich/juice-shop:v20.0.0` and run it, then poll `/rest/admin/application-version` up to 60s -- Fail the job if the endpoint never returns HTTP 200 - ---- - -## Commands run (copyable) - -```bash -docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v20.0.0 -docker ps --filter name=juice-shop --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' -curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000 -curl -s http://127.0.0.1:3000/api/Products | jq '.data | length' -curl -s http://127.0.0.1:3000/rest/admin/application-version | jq -``` - -Replace host-specific fields (image digest, host OS, exact docker ps uptime) with the outputs from running these commands on your machine. - ---- - -## Cleanup - -```bash -docker stop juice-shop || true -# docker rm juice-shop # optional -``` From b2b840a860e93e1e5e4581760f3c42d1396d64c7 Mon Sep 17 00:00:00 2001 From: diffouo44 Date: Wed, 10 Jun 2026 18:07:40 +0300 Subject: [PATCH 2/4] Remove pull request template from main branch --- .github/PULL_REQUEST_TEMPLATE.md | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 79b9477e8..000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,17 +0,0 @@ -## Pull Request Template - -## Goal -One-sentence description of what this PR delivers. - -## Changes -- List files added or modified - -## Testing -- Commands run and observed output - -## Artifacts & Screenshots -- Links to submission files and images - -- [ ] Title uses `feat(labN): ` style -- [ ] No secrets/large temp files committed -- [ ] `submissions/labN.md` present \ No newline at end of file From c8eb829c551a774266a2b7e49d535a7af482c0b1 Mon Sep 17 00:00:00 2001 From: diffouo44 Date: Wed, 10 Jun 2026 21:52:51 +0300 Subject: [PATCH 3/4] feat(lab2): Threagile threat model + secure variant + auth flow --- labs/lab2/threagile-model-auth.yaml | 208 ++++++++++++ labs/lab2/threagile-model-secure.yaml | 446 ++++++++++++++++++++++++++ submissions/lab2.md | 86 +++++ 3 files changed, 740 insertions(+) create mode 100644 labs/lab2/threagile-model-auth.yaml create mode 100644 labs/lab2/threagile-model-secure.yaml create mode 100644 submissions/lab2.md diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..cb5da7e0c --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,208 @@ +threagile_version: 1.0.0 +title: Juice Shop Auth Focused Model +date: 2026-06-10 +management_summary_comment: > + Focused model for authentication flow used in Lab 2 bonus task. + +business_criticality: important + +data_assets: + credentials: + id: credentials + description: "Username and password credentials submitted by users." + usage: business + owner: Lab Student + quantity: few + confidentiality: restricted + integrity: operational + availability: operational + justification_cia_rating: "Credentials are sensitive and need protection." + jwt-token: + id: jwt-token + description: "JWT issued by the auth service and used for API calls." + usage: business + owner: Lab Student + quantity: few + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "Tokens grant access and must be protected." + user-session: + id: user-session + description: "Session state stored by the auth/API for logged-in users." + usage: business + owner: Lab Student + quantity: many + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "Session state is needed for authentication continuity." + +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 + size: system + technology: browser + tags: [] + internet: true + machine: virtual + encryption: none + owner: Lab Student + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user." + data_assets_processed: + - credentials + communication_links: + Browser->Auth: + target: auth-api + description: "User submits credentials to Auth API (login/register)." + protocol: https + authentication: none + authorization: none + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + + Auth API: + id: auth-api + description: "Authentication API endpoint (issues JWTs)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Auth API handles authentication flows." + data_assets_processed: + - credentials + - jwt-token + communication_links: + Auth->TokenSigner: + target: token-signer + description: "Requests JWT signing from the token service." + protocol: https + authentication: none + authorization: technical-user + usage: business + data_assets_sent: + - jwt-token + Auth->UserDB: + target: user-db + description: "Verify credentials against user database using parameterized queries." + protocol: jdbc-encrypted + authentication: credentials + authorization: technical-user + usage: business + data_assets_sent: + - credentials + + Token Signer: + id: token-signer + description: "Service that issues and verifies JWTs (holds signing keys)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "Holds signing keys; high integrity requirement." + data_assets_processed: + - jwt-token + + User DB: + id: user-db + description: "Database storing user credential hashes and profile data." + type: datastore + usage: devops + used_as_client_by_human: false + out_of_scope: false + size: component + technology: database + tags: [] + internet: false + machine: virtual + encryption: data-with-symmetric-shared-key + owner: Lab Student + confidentiality: restricted + integrity: important + availability: important + justification_cia_rating: "Contains credential hashes and PII." + data_assets_stored: + - credentials + + Admin Endpoint: + id: admin-endpoint + description: "Admin UI/API that requires admin-role via JWT." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: restricted + integrity: important + availability: important + justification_cia_rating: "Admin functions require elevated protection." + communication_links: + Admin->TokenSigner: + target: token-signer + description: "Token verification requests." + protocol: https + authentication: token + authorization: enduser-identity-propagation + usage: business + +trust_boundaries: + Internet: + id: internet + description: "Untrusted public network." + type: network-dedicated-hoster + technical_assets_inside: + - user-browser + + Container Network: + id: container-network + description: "Container network hosting services." + type: network-dedicated-hoster + technical_assets_inside: + - auth-api + - token-signer + - user-db + - admin-endpoint + +shared_runtimes: {} + +# Minimal metadata +name: Juice Shop Auth Flow (focused) +version: 1.0 diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..9a708907d --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,446 @@ +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 (HTTPS 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 (HTTPS on 3000 internally)." + protocol: https + authentication: session-id + authorization: technical-user + 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: data-with-symmetric-shared-key + 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 DB: + target: persistent-storage + description: "App uses prepared statements / parameterized queries when accessing the database." + protocol: jdbc-encrypted + authentication: credentials + authorization: technical-user + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - user-accounts + - orders + - product-catalog + - tokens-sessions + data_assets_received: + - 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: 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..2ced25464 --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,86 @@ +# Lab 2 Submission + +## Task 1: Baseline Threat Model + +### Risk count by severity +| Severity | Count | +|----------|------:| +| Elevated | 4 | +| Medium | 14 | +| Low | 5 | +| **Total** | **23** | + +### Top 5 risks (paste from `jq` output) +1. **missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application; severity elevated; affecting `juice-shop` +2. **cross-site-scripting@juice-shop** — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity elevated; affecting `juice-shop` +3. **unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop** — Unencrypted Communication on Direct to App (no proxy) between User Browser and Juice Shop Application; severity elevated; affecting `user-browser` +4. **unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Unencrypted Communication on To App between Reverse Proxy and Juice Shop Application; severity elevated; affecting `reverse-proxy` +5. **unencrypted-asset@juice-shop** — Unencrypted Technical Asset named Juice Shop Application; severity medium; affecting `juice-shop` + +### STRIDE mapping (Lecture 2 slide 7) +- missing-authentication: **A** — attacker can bypass authentication on the app-facing reverse-proxy link. +- cross-site-scripting: **S** — attacker can inject script into the browser session and act as the user. +- unencrypted communication (Direct to App): **I/D** — unprotected traffic can be intercepted or modified. +- unencrypted communication (To App): **I/D** — internal HTTP traffic exposes session/token traffic in the container network. +- unencrypted asset (Juice Shop Application): **D** — the app asset is not encrypted and sensitive data can be disclosed. + +### Trust boundary observation +The `Direct to App (no proxy)` arrow crosses the untrusted Internet trust boundary directly into `Juice Shop Application`. This path is attractive because it bypasses the reverse proxy controls and exposes authentication/session data to attackers. + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 3 | -1 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total** | **23** | **21** | **-2** | + +The secure variant was implemented by hardening `Direct to App (no proxy)` and `To App` to HTTPS, enabling encryption on `Persistent Storage`, and adding a database access link with prepared-statement documentation in the description. + + +### Which rules are GONE in the secure variant? +1. `unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop` — fixed by switching direct browser-to-app traffic to `protocol: https`. +2. `unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop` — fixed by changing the proxy→app link to `protocol: https` and adding link-level authentication. +3. `missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop` — fixed by introducing authentication/authorization controls on the reverse-proxy→app communication link. + +### Which rules are STILL THERE in the secure variant? +1. `cross-site-scripting@juice-shop` — The application still processes untrusted input in contexts that allow script execution; transport and storage improvements do not eliminate injection vulnerabilities. Fixing this requires code changes (input validation and output encoding) and runtime policies such as a Content Security Policy to reduce impact. + +2. `missing-identity-store@reverse-proxy` — The model still lacks a centralized identity store, so identity lifecycle and authoritative authentication are not enforced by design. Introducing an identity provider and integrating it into the architecture is required to address this risk, which is a larger design change beyond simple configuration. + +### Honesty check +No — the total risk count dropped only slightly (from 23 to 21, ~8.7%), which is well below a 50% reduction. This indicates that the targeted hardening steps (HTTPS, storage encryption, database access controls) produced modest improvements for transport and storage risks, but many remaining risks are application-level and require more invasive work (code fixes, identity integration, build hardening) with higher development cost. The cost-benefit therefore favors pairing infrastructure hardening with prioritized application fixes rather than attempting to eliminate all risks through infrastructure changes alone. + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Elevated | 1 | +| Medium | 11 | +| Low | 6 | +| **Total** | **18** | + +### Three auth-specific risks (NOT in the baseline model's top 5) +For each, name: +- The rule ID Threagile fires +- The STRIDE letter +- A 1-2 sentence mitigation in plain English + +1. **sql-nosql-injection@auth-api@user-db@auth-api>auth-userdb** — STRIDE: T — Mitigation: Use parameterized queries / prepared statements and validate input strictly on the Auth API. Additionally, run the Auth API with a least-privilege DB account and restrict DB permissions to only what's necessary. + +2. **missing-identity-store@token-signer** — STRIDE: S — Mitigation: Introduce a centralized identity provider or identity store to manage credentials and identity lifecycle for the authentication components. Integrate service authentication and rotate credentials centrally so tokens and keys are managed and audited. + +3. **missing-authentication@auth-api>auth-tokensigner@auth-api@token-signer** — STRIDE: S — Mitigation: Require authenticated, authorized service-to-service calls (for example mTLS or signed service tokens) between the Auth API and the Token Signer, and enforce authorization checks. Also restrict network access so only the Auth API can reach the Token Signer. + +### Reflection (2-3 sentences) +Building a focused auth model revealed that many high-impact risks concentrate around credential handling, token issuance, and database access. Infrastructure hardening alone is insufficient; secure authentication needs careful design (identity stores, authenticated service-to-service calls, parameterized DB access) and code-level fixes to fully mitigate these risks. + + + From 7d66e64037f04d15cb0f291d0dd6fbd43a83d199 Mon Sep 17 00:00:00 2001 From: diffouo44 Date: Wed, 10 Jun 2026 22:10:30 +0300 Subject: [PATCH 4/4] feat(lab2): Threagile threat model + secure variant + auth flow --- labs/lab2/threagile-model-auth.yaml | 20 ++++++++++++++++++++ submissions/lab2.md | 18 +++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml index cb5da7e0c..22cdcd368 100644 --- a/labs/lab2/threagile-model-auth.yaml +++ b/labs/lab2/threagile-model-auth.yaml @@ -38,6 +38,17 @@ data_assets: availability: operational justification_cia_rating: "Session state is needed for authentication continuity." + refresh-token: + id: refresh-token + description: "Long-lived refresh tokens used to obtain new JWTs without re-authentication." + usage: business + owner: Lab Student + quantity: few + confidentiality: restricted + integrity: important + availability: operational + justification_cia_rating: "Refresh tokens allow session continuation and must be protected and stored securely." + technical_assets: User Browser: @@ -134,6 +145,7 @@ technical_assets: justification_cia_rating: "Holds signing keys; high integrity requirement." data_assets_processed: - jwt-token + - refresh-token User DB: id: user-db @@ -155,6 +167,7 @@ technical_assets: justification_cia_rating: "Contains credential hashes and PII." data_assets_stored: - credentials + - refresh-token Admin Endpoint: id: admin-endpoint @@ -182,6 +195,13 @@ technical_assets: authentication: token authorization: enduser-identity-propagation usage: business + Admin->UserDB: + target: user-db + description: "Admin queries to inspect or manage user records." + protocol: jdbc-encrypted + authentication: token + authorization: admin-role + usage: business trust_boundaries: Internet: diff --git a/submissions/lab2.md b/submissions/lab2.md index 2ced25464..86c2c3af3 100644 --- a/submissions/lab2.md +++ b/submissions/lab2.md @@ -11,18 +11,18 @@ | **Total** | **23** | ### Top 5 risks (paste from `jq` output) -1. **missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application; severity elevated; affecting `juice-shop` -2. **cross-site-scripting@juice-shop** — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity elevated; affecting `juice-shop` -3. **unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop** — Unencrypted Communication on Direct to App (no proxy) between User Browser and Juice Shop Application; severity elevated; affecting `user-browser` -4. **unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Unencrypted Communication on To App between Reverse Proxy and Juice Shop Application; severity elevated; affecting `reverse-proxy` -5. **unencrypted-asset@juice-shop** — Unencrypted Technical Asset named Juice Shop Application; severity medium; affecting `juice-shop` +1. **unencrypted-asset@juice-shop** — Unencrypted Technical Asset named Juice Shop Application; severity medium; affecting `juice-shop` +2. **unencrypted-asset@persistent-storage** — Unencrypted Technical Asset named Persistent Storage; severity medium; affecting `persistent-storage` +3. **missing-identity-store@reverse-proxy** — Missing Identity Store in the threat model (example asset Reverse Proxy); severity medium; affecting `reverse-proxy` +4. **missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application; severity elevated; affecting `juice-shop` +5. **cross-site-request-forgery@juice-shop@user-browser>direct-to-app-no-proxy** — Cross-Site Request Forgery risk involving the Direct-to-App (no proxy) path; severity medium; affecting `juice-shop` ### STRIDE mapping (Lecture 2 slide 7) - missing-authentication: **A** — attacker can bypass authentication on the app-facing reverse-proxy link. -- cross-site-scripting: **S** — attacker can inject script into the browser session and act as the user. -- unencrypted communication (Direct to App): **I/D** — unprotected traffic can be intercepted or modified. -- unencrypted communication (To App): **I/D** — internal HTTP traffic exposes session/token traffic in the container network. -- unencrypted asset (Juice Shop Application): **D** — the app asset is not encrypted and sensitive data can be disclosed. +- cross-site-request-forgery: **S** — an attacker can cause a user's browser to perform actions without their intent, effectively acting as the user. +- unencrypted communication (Direct to App): **I/D** — unprotected traffic can be intercepted (Disclosure) or modified (Tampering). +- unencrypted communication (To App): **I/D** — internal HTTP traffic exposes session/token traffic in the container network to interception or modification. +- unencrypted asset (Juice Shop Application / Persistent Storage): **D** — the asset is not encrypted and sensitive data can be disclosed if accessed. ### Trust boundary observation The `Direct to App (no proxy)` arrow crosses the untrusted Internet trust boundary directly into `Juice Shop Application`. This path is attractive because it bypasses the reverse proxy controls and exposes authentication/session data to attackers.