From 6f8d408fa6f358ce6636d77d30599ebe0a6f11b9 Mon Sep 17 00:00:00 2001 From: ShumakovMikhail Date: Sat, 6 Jun 2026 17:07:51 +0300 Subject: [PATCH 1/3] feat(lab2): Threagile threat model + secure variant + auth flow --- labs/lab2/threagile-model-auth.yaml | 410 ++++++++++++++++++++++++ labs/lab2/threagile-model-secure.yaml | 429 ++++++++++++++++++++++++++ submissions/lab2.md | 100 ++++++ 3 files changed, 939 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..7e65213dc --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,410 @@ +threagile_version: 1.0.0 + +title: Juice Shop — Authentication Flow Threat Model +date: 2026-06-06 + +author: + name: Mikhail Shumakov + homepage: https://github.com/0xsmk + +management_summary_comment: > + Focused threat model on Juice Shop authentication flow: login, JWT issuance, + session management, and access to admin endpoints. + +business_criticality: critical + +business_overview: + description: > + Models the authentication and authorization flow of OWASP Juice Shop. + Covers credential submission, JWT token issuance, session handling, + and admin endpoint access control. + +technical_overview: + description: > + Browser submits credentials to Auth API. Auth API verifies against User DB + and issues a JWT signed by Token Signer. Browser stores JWT and sends it + with subsequent requests. Admin endpoints verify JWT contains admin role. + +questions: {} +abuse_cases: + JWT Forgery: > + Attacker forges or tampers with JWT to gain admin privileges. + Credential Brute Force: > + Attacker attempts repeated logins to guess user passwords. + SQL Injection on Login: > + Attacker injects SQL into login form to bypass authentication. + Privilege Escalation via JWT: > + Attacker modifies JWT payload to elevate role to admin. + +security_requirements: + Strong JWT signing: Use RS256 or HS256 with a strong secret; validate signature on every request. + Rate limiting on login: Prevent brute force with rate limiting and account lockout. + Parameterized queries: Use prepared statements on all DB queries including login. + Admin role verification: Server-side role check on every admin endpoint request. + +tags_available: + - browser + - auth + - jwt + - api + - db + - admin + - credentials + - tokens + - pii + +data_assets: + + Credentials: + id: credentials + description: "Username and password submitted by user during login or registration." + usage: business + tags: ["auth", "pii"] + origin: user-supplied + owner: User + quantity: many + confidentiality: strictly-confidential + integrity: critical + availability: important + justification_cia_rating: > + Credentials are the primary authentication factor. Exposure leads to account takeover. + + JWT Token: + id: jwt-token + description: "JSON Web Token issued after successful login, used to authorize subsequent requests." + usage: business + tags: ["auth", "tokens"] + origin: application + owner: Juice Shop + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + JWT tokens grant access to protected resources. Tampering or theft enables session hijacking. + + JWT Signing Key: + id: jwt-signing-key + description: "Secret key used to sign and verify JWT tokens." + usage: devops + tags: ["auth", "tokens"] + origin: application + owner: Juice Shop + quantity: very-few + confidentiality: strictly-confidential + integrity: critical + availability: critical + justification_cia_rating: > + Compromise of the signing key allows forging arbitrary tokens including admin tokens. + + User Session State: + id: user-session-state + description: "Server-side session data and user identity context." + usage: business + tags: ["auth"] + origin: application + owner: Juice Shop + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + Session state links user identity to active requests; tampering enables impersonation. + + Admin Operation Requests: + id: admin-operation-requests + description: "Requests to admin endpoints (user management, challenge flags, config)." + usage: business + tags: ["admin", "auth"] + origin: user-supplied + owner: Admin User + quantity: few + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + Admin operations are privileged; unauthorized access leads to full application compromise. + +technical_assets: + + Browser: + id: browser + description: "End-user web browser submitting credentials and carrying JWT." + 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"] + internet: true + machine: virtual + encryption: none + owner: External User + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user — treat as untrusted." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + - jwt-token + data_assets_stored: + - jwt-token + data_formats_accepted: + - json + communication_links: + Login Request: + target: auth-api + description: "Browser sends credentials to Auth API over HTTP (unauthenticated endpoint)." + protocol: http + authentication: none + 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 to access protected resources." + protocol: http + authentication: token + authorization: enduser-identity-propagation + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - jwt-token + data_assets_received: + - user-session-state + Admin Endpoint Request: + target: admin-endpoint + description: "Browser requests admin operations with JWT containing admin role claim." + protocol: http + authentication: token + authorization: enduser-identity-propagation + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - jwt-token + - admin-operation-requests + data_assets_received: [] + + Auth API: + id: auth-api + description: "Juice Shop authentication endpoint handling login, registration, JWT issuance and verification." + 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: ["api", "auth"] + internet: false + machine: container + encryption: none + owner: Juice Shop + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Central auth component — compromise leads to full account takeover." + 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: + Verify Credentials: + target: user-db + description: "Auth API queries User DB to verify submitted credentials. Uses string concatenation in SQL (no prepared statements)." + protocol: jdbc + authentication: token + authorization: technical-user + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - credentials + data_assets_received: + - user-session-state + Request JWT Signing: + target: token-signer + description: "Auth API requests Token Signer to sign a JWT payload after successful credential verification." + 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 JWT tokens 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: ["auth", "tokens"] + internet: false + machine: container + encryption: none + owner: Juice Shop + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Holds signing key — highest value target in the auth flow." + 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 DB: + id: user-db + description: "SQLite database storing user credentials and 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: ["db", "auth", "pii"] + internet: false + machine: virtual + encryption: none + owner: Juice Shop + confidentiality: strictly-confidential + integrity: critical + availability: important + justification_cia_rating: "Contains credential hashes and PII — primary target for SQL injection attacks." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - credentials + - user-session-state + data_assets_stored: + - credentials + - user-session-state + data_formats_accepted: + - file + communication_links: {} + + Admin Endpoint: + id: admin-endpoint + description: "Privileged admin API endpoints (user management, challenge control, config)." + 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", "api"] + internet: false + machine: container + encryption: none + owner: Juice Shop + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Admin operations are privileged — unauthorized access causes full application compromise." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - jwt-token + - admin-operation-requests + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + Verify JWT for Admin: + target: token-signer + description: "Admin endpoint sends JWT to Token Signer for verification of signature and admin role claim." + 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: + - user-session-state + +trust_boundaries: + + Internet: + id: internet + description: "Untrusted public network." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - browser + trust_boundaries_nested: + - container-network + + Container Network: + id: container-network + description: "Docker container network running Juice Shop auth components." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - auth-api + - token-signer + - user-db + - admin-endpoint + trust_boundaries_nested: [] + +shared_runtimes: + Docker Host: + id: docker-host + description: "Docker engine running all Juice Shop auth containers." + tags: [] + technical_assets_running: + - auth-api + - token-signer + - 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..0fd43a51b --- /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 (HTTPS internally). App uses parameterized queries (prepared statements) for all DB operations to prevent SQL injection." + protocol: https + authentication: token + 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: 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 + encryption: data-with-symmetric-shared-key + tags: ["storage", "volume"] + internet: false + machine: virtual + 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..4815cb951 --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,100 @@ +# 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. **cross-site-scripting** — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity: elevated; affecting: juice-shop +2. **unencrypted-communication** — Unencrypted Communication named "Direct to App (no proxy)" between User Browser and Juice Shop Application transferring authentication data; severity: elevated; affecting: user-browser +3. **unencrypted-communication** — Unencrypted Communication named "To App" between Reverse Proxy and Juice Shop Application; severity: elevated; affecting: reverse-proxy +4. **missing-authentication** — Missing Authentication covering communication link "To App" from Reverse Proxy to Juice Shop Application; severity: elevated; affecting: juice-shop +5. **server-side-request-forgery** — SSRF risk at Reverse Proxy server-side web-requesting Juice Shop Application via "To App"; severity: medium; affecting: reverse-proxy + +### STRIDE mapping + +- Risk 1 (cross-site-scripting): **T (Tampering)** — Attacker injects malicious scripts into page content, tampering with data seen by other users and stealing their session tokens. +- Risk 2 (unencrypted-communication, direct): **I (Information Disclosure)** — HTTP traffic between browser and app is unencrypted; credentials and session tokens transmitted in plaintext are visible to network observers. +- Risk 3 (unencrypted-communication, proxy→app): **I (Information Disclosure)** — Internal proxy-to-app leg uses HTTP; any attacker with access to the host network can intercept tokens and session data in transit. +- Risk 4 (missing-authentication): **S (Spoofing)** — The proxy-to-app link has no authentication; any process on the host network can impersonate the proxy and send unauthenticated requests directly to the app. +- Risk 5 (server-side-request-forgery): **S (Spoofing)** — The reverse proxy can be abused to make server-side requests to internal resources, allowing an attacker to spoof the proxy identity and reach internal services. + +### Trust boundary observation + +Looking at data-flow-diagram.png, the arrow "Direct to App (no proxy)" crosses the trust boundary from Internet (User Browser) directly into the Container Network (Juice Shop Application) over plain HTTP. This arrow is particularly attractive to an attacker because it bypasses the reverse proxy entirely — no TLS termination, no security headers, no authentication — meaning credentials and session tokens flow in plaintext across the most exposed boundary in the architecture. + +--- + +## Task 2: Secure Variant & Diff + +### Changes made to threagile-model-secure.yaml + +1. All protocol: http communication links changed to protocol: https +2. Persistent Storage encryption changed from none to data-with-symmetric-shared-key +3. Proxy→App link authentication changed from none to token +4. Proxy→App link authorization changed from none to technical-user +5. Proxy→App description updated to declare use of parameterized queries (prepared statements) + +### Risk count comparison + +| Severity | Baseline | Secure | Δ | +|----------|--------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 1 | -3 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total** | **23** | **19** | **-4** | + +### Which rules are GONE in the secure variant? + +1. unencrypted-communication (Direct to App) — fixed by changing protocol: http to protocol: https on the Browser→App direct link +2. unencrypted-communication (Proxy→App) — fixed by changing protocol: http to protocol: https on the Proxy→App internal link +3. missing-authentication (Proxy→App) — fixed by adding authentication: token and authorization: technical-user on the Proxy→App link + +### Which rules are STILL THERE in the secure variant? + +1. cross-site-scripting at Juice Shop Application — XSS is an application-level vulnerability caused by insufficient output encoding in the app code. Switching to HTTPS and encrypting storage does not affect how the app handles user-supplied input in HTML rendering; this risk requires code-level fixes (output escaping, CSP headers) that cannot be expressed through Threagile communication link fields alone. + +2. missing-build-infrastructure — This risk fires because the threat model declares no CI/CD pipeline or build system asset. Adding HTTPS and encryption to communication links does not introduce a build infrastructure component into the architecture; a separate set of changes would be needed to suppress this rule. + +### Honesty check + +The total dropped by 4 risks (about 17%), not more than 50%. This tells us that the five hardening changes address only the most obvious transport-layer and authentication gaps. The remaining 19 risks are architectural and application-level issues (XSS, missing vault, missing WAF, SSRF, container hardening) that require deeper engineering investment: secure coding practices, secret management infrastructure, network segmentation, and WAF deployment. The cost-benefit is strong for the changes made (low effort, high signal on elevated risks), but the bulk of the risk surface requires sustained engineering work, not just configuration tweaks. + +--- + +## Bonus Task: Auth Flow Threat Model + +### Risk count + +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 1 | +| Elevated | 9 | +| Medium | 18 | +| Low | 8 | +| **Total** | **36** | + +### Three auth-specific risks NOT in the baseline top 5 + +1. **sql-nosql-injection** — STRIDE: **T (Tampering)** — The Auth API queries User DB using string-concatenated SQL with user-supplied credentials, allowing an attacker to inject OR 1=1 into the login form to bypass authentication entirely. Mitigation: replace all dynamic SQL with parameterized queries (prepared statements) in the login and registration handlers. + +2. **unguarded-access-from-internet** — STRIDE: **E (Elevation of Privilege)** — The Auth API and Admin Endpoint are directly reachable from the Internet trust boundary without any WAF, rate limiter, or API gateway in front, allowing attackers to brute-force credentials or attempt JWT forgery attacks at full speed. Mitigation: place a WAF or API gateway with rate limiting and IP-based throttling in front of all auth endpoints. + +3. **missing-hardening** at User DB — STRIDE: **I (Information Disclosure)** — The User DB (SQLite) runs without hardening controls: no encryption at rest, no access controls beyond the container boundary, and no audit logging of credential queries. If an attacker gains container access they can read the raw credential hashes directly from the database file. Mitigation: enable encryption at rest for the database file, restrict DB file permissions to the app process only, and log all authentication queries for anomaly detection. + +### Reflection + +Building the focused auth model surfaced risks that the baseline architecture model missed entirely because the baseline treated the entire Juice Shop as a single process asset without modelling the internal auth components separately. By decomposing the flow into Browser → Auth API → Token Signer → User DB → Admin Endpoint, Threagile was able to fire SQL injection, unguarded internet access, and missing hardening rules that are invisible when auth logic is hidden inside a monolithic asset. Feature-level threat models consistently find implementation-level risks that architecture-level models cannot see because they lack the resolution to distinguish one API endpoint from another. From a938eeccf0e8efbf0afda7d48e54e6f5bb36d200 Mon Sep 17 00:00:00 2001 From: ShumakovMikhail Date: Wed, 17 Jun 2026 19:50:56 +0300 Subject: [PATCH 2/3] test: first signed commit --- submissions/lab3.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 submissions/lab3.md diff --git a/submissions/lab3.md b/submissions/lab3.md new file mode 100644 index 000000000..61fa24bee --- /dev/null +++ b/submissions/lab3.md @@ -0,0 +1 @@ +lab3 signing test From e04ad2eb96de2b9faeaa870a617a64c665b08f1f Mon Sep 17 00:00:00 2001 From: ShumakovMikhail Date: Wed, 17 Jun 2026 20:10:56 +0300 Subject: [PATCH 3/3] feat(lab3): add SSH signing and secret scanning --- .pre-commit-config.yaml | 12 +++++ submissions/lab3.md | 111 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..bef15f207 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,12 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.1 + hooks: + - id: gitleaks + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: detect-private-key + exclude: ^labs/lab6/vulnerable-iac/ansible/configure\.yml$ + - id: check-added-large-files diff --git a/submissions/lab3.md b/submissions/lab3.md index 61fa24bee..c69d09ac8 100644 --- a/submissions/lab3.md +++ b/submissions/lab3.md @@ -1 +1,110 @@ -lab3 signing test +# Lab 3 — Submission + +## Task 1: SSH Commit Signing + +### Local configuration + +- `git config --global gpg.format` → `ssh` +- `git config --global user.signingkey` → `/Users/msumakov366gmail.com/.ssh/id_ed25519.pub` +- `git config --global commit.gpgsign` → `true` + +### Local verification + +```text +Good "git" signature for msumakov366@gmail.com (key fingerprint omitted) +``` + +### GitHub verification + +- Verified commit: https://github.com/0xsmk/DevSecOps-Intro/commit/a938eeccf0e8efbf0afda7d48e54e6f5bb36d200 + +### Reflection + +A forged-author commit could make malicious code appear to have been approved or written by a trusted teammate, allowing the attacker to deny responsibility while shifting blame. The Verified badge cryptographically connects the commit to a registered signing key, making an unsigned or incorrectly signed impersonation visible during review. + +## Task 2: Pre-commit + gitleaks + +### `.pre-commit-config.yaml` + +```yaml +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.1 + hooks: + - id: gitleaks + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: detect-private-key + exclude: ^labs/lab6/vulnerable-iac/ansible/configure\.yml$ + - id: check-added-large-files +``` + +### Installation + +```text +pre-commit installed at .git/hooks/pre-commit +``` + +### Blocked commit + +```text +Detect hardcoded secrets.................................................Failed +- hook id: gitleaks +- exit code: 1 + +Finding: GH_PAT=REDACTED +Secret: REDACTED +RuleID: github-pat +Entropy: 4.143943 +File: submissions/leak-attempt.txt +Line: 2 +Fingerprint: submissions/leak-attempt.txt:github-pat:2 + +8:03PM INF 0 commits scanned. +8:03PM INF scanned ~83 bytes (83 bytes) in 28.7ms +8:03PM WRN leaks found: 1 +``` + +### Tune-out exercise + +An inline allowlist in `.gitleaks.toml` is appropriate for a narrowly identified and verified fake example whose exact value or rule can be excluded. The exception should remain specific and documented so that similar real credentials are still detected. + +A path exclusion such as `docs/` can be convenient when an entire generated documentation tree contains many false positives. It is risky because a real credential placed anywhere under that path will also avoid scanning, creating a broad blind spot. + +## Bonus: History Rewrite + +### Before + +```text +249d264 docs: add usage notes +67bede0 feat: empty log +d08a259 feat: add config +fe25519 init +``` + +Output of `git log -p | grep -c 'ghp_'`: **2** + +### After + +```text +db27279 docs: add usage notes +5527da2 feat: empty log +cdbf9c6 feat: add config +4d69f10 init +``` + +Output of `git log -p | grep -c 'ghp_'`: **0** + +Output of `git log -p | grep -c 'REDACTED'`: **2** + +### The two-step pattern in real life + +1. Run `git filter-repo --replace-text replacements.txt` and force-push the rewritten history. +2. Immediately revoke or rotate the exposed credential because rewriting history does not invalidate copies already fetched, cached, or logged elsewhere. + +### Two real-world gotchas + +1. `git filter-repo` refused to rewrite the locally created repository because it was not considered a fresh clone. Since this was a disposable sandbox, I had to explicitly use `--force`. +2. Every rewritten commit received a new hash, including commits whose visible files were not directly edited. Existing links and references to the old commit IDs therefore became obsolete.