diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..099aafa4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,74 @@ +# Lab Submission Pull Request + +## Goal + +**Lab Number:** +**Lab Title:** + +**Objective:** + + +--- + +## Changes + +**Summary of modifications:** + +- +- +- + +**Files Added/Modified:** + +- +- +- + +--- + +## Testing + +**How were the changes verified?** + +- +- +- + +**Test Results:** + +- + +--- + +## Artifacts & Screenshots + +**Evidence of completion:** + +- +- +- + +**Key Deliverables:** + +- [ ] Task 1: +- [ ] Task 2: +- [ ] Additional tasks: + +--- + +## Checklist + +Before submitting this PR, please verify: + +- [ ] PR title is clear and descriptive (e.g., "docs(lab1): add submission1 triage report") +- [ ] Documentation has been updated if needed (README, submission files, etc.) +- [ ] No secrets, credentials, or large temporary files are included in the commit +- [ ] All required tasks from the lab assignment are completed +- [ ] Screenshots and evidence are properly embedded or linked + +--- + +## Additional Notes + + + diff --git a/labs/lab1-cleanup.sh b/labs/lab1-cleanup.sh new file mode 100755 index 00000000..60a0be20 --- /dev/null +++ b/labs/lab1-cleanup.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# +# OWASP Juice Shop Cleanup Script for Lab 1 +# +# This script removes the Juice Shop container and optionally the image. +# Use this after completing the lab to free up system resources. +# +# Usage: bash labs/lab1-cleanup.sh [--remove-image] +# + +set -e # Exit on any error + +# Configuration +CONTAINER_NAME="juice-shop" +IMAGE_NAME="bkimminich/juice-shop" +IMAGE_TAG="v19.0.0" +FULL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +REMOVE_IMAGE=false + +# Parse arguments +if [ "$1" == "--remove-image" ]; then + REMOVE_IMAGE=true +fi + +echo "================================================" +echo "OWASP Juice Shop Cleanup Script" +echo "================================================" +echo "" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo "ERROR: Docker is not installed or not in PATH" + exit 1 +fi + +# Stop and remove container +echo "[1/2] Removing Juice Shop container..." +if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo " Found container: ${CONTAINER_NAME}" + + # Stop if running + if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo " Stopping running container..." + docker stop "${CONTAINER_NAME}" &> /dev/null + fi + + # Remove container + echo " Removing container..." + docker rm "${CONTAINER_NAME}" &> /dev/null + echo "Container removed successfully" +else + echo "No container named '${CONTAINER_NAME}' found (already clean)" +fi +echo "" + +# Remove image if requested +if [ "$REMOVE_IMAGE" == true ]; then + echo "[2/2] Removing Juice Shop image..." + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${FULL_IMAGE}$"; then + echo " Found image: ${FULL_IMAGE}" + echo " Removing image..." + docker rmi "${FULL_IMAGE}" &> /dev/null + echo "Image removed successfully" + else + echo "Image '${FULL_IMAGE}' not found (already removed or never pulled)" + fi +else + echo "[2/2] Keeping Docker image" + echo " Image '${FULL_IMAGE}' preserved for future use" + echo " To remove image, run: bash labs/lab1-cleanup.sh --remove-image" +fi +echo "" + +echo "================================================" +echo "Cleanup Complete!" +echo "================================================" +echo "" +echo "What was cleaned:" +if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo " Container: Still exists (unexpected)" +else + echo " Container: Removed" +fi + +if [ "$REMOVE_IMAGE" == true ]; then + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${FULL_IMAGE}$"; then + echo " Image: Still exists (unexpected)" + else + echo " Image: Removed" + fi +else + echo " Image: Preserved (not removed)" +fi +echo "" diff --git a/labs/lab1-deploy.sh b/labs/lab1-deploy.sh new file mode 100755 index 00000000..32e94475 --- /dev/null +++ b/labs/lab1-deploy.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# +# OWASP Juice Shop Deployment Script for Lab 1 +# +# This script deploys OWASP Juice Shop v19.0.0 locally for security testing. +# The container is bound to 127.0.0.1 only to prevent external exposure. +# +# Usage: bash labs/lab1-deploy.sh +# + +set -e # Exit on any error + +# Configuration +CONTAINER_NAME="juice-shop" +IMAGE_NAME="bkimminich/juice-shop" +IMAGE_TAG="v19.0.0" +FULL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +HOST_IP="127.0.0.1" +HOST_PORT="3000" +CONTAINER_PORT="3000" + +echo "================================================" +echo "OWASP Juice Shop Deployment Script" +echo "================================================" +echo "" + +# Check if Docker is installed and running +echo "[1/5] Checking Docker installation..." +if ! command -v docker &> /dev/null; then + echo "ERROR: Docker is not installed or not in PATH" + echo " Please install Docker Desktop from https://www.docker.com/products/docker-desktop" + exit 1 +fi + +if ! docker info &> /dev/null; then + echo "ERROR: Docker daemon is not running" + echo " Please start Docker Desktop and try again" + exit 1 +fi +echo "Docker is installed and running" +echo "" + +# Check if container already exists +echo "[2/5] Checking for existing Juice Shop container..." +if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo "Container '${CONTAINER_NAME}' already exists" + echo " Removing existing container..." + docker rm -f "${CONTAINER_NAME}" &> /dev/null + echo "Existing container removed" +else + echo "No existing container found" +fi +echo "" + +# Pull the image +echo "[3/5] Pulling OWASP Juice Shop image..." +echo " Image: ${FULL_IMAGE}" +docker pull "${FULL_IMAGE}" +echo "Image pulled successfully" +echo "" + +# Get image digest for triage report +echo "[4/5] Retrieving image digest..." +IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "${FULL_IMAGE}" 2>/dev/null || echo "N/A") +echo " Digest: ${IMAGE_DIGEST}" +echo "" + +# Deploy the container +echo "[5/5] Deploying Juice Shop container..." +echo " Container name: ${CONTAINER_NAME}" +echo " Network binding: ${HOST_IP}:${HOST_PORT}" +echo " Security: Bound to localhost only (no external exposure)" +echo "" + +docker run -d \ + --name "${CONTAINER_NAME}" \ + -p "${HOST_IP}:${HOST_PORT}:${CONTAINER_PORT}" \ + "${FULL_IMAGE}" + +# Wait for container to start +echo "Waiting for container to start (5 seconds)..." +sleep 5 + +# Verify container is running +if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo "Container deployed successfully!" +else + echo "ERROR: Container failed to start" + echo " Check logs with: docker logs ${CONTAINER_NAME}" + exit 1 +fi + +echo "" +echo "================================================" +echo "Deployment Complete!" +echo "================================================" +echo "" +echo "Deployment Summary:" +echo " • Container: ${CONTAINER_NAME}" +echo " • Image: ${FULL_IMAGE}" +echo " • Digest: ${IMAGE_DIGEST}" +echo " • Access URL: http://${HOST_IP}:${HOST_PORT}" +echo " • Status: Running" +echo "" diff --git a/labs/lab1-verify.sh b/labs/lab1-verify.sh new file mode 100755 index 00000000..e3b92c97 --- /dev/null +++ b/labs/lab1-verify.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# +# OWASP Juice Shop Verification Script for Lab 1 +# +# This script performs health checks and security verification for the deployed Juice Shop. +# Use the output for your triage report in labs/submission1.md +# +# Usage: bash labs/lab1-verify.sh +# + +set -e # Exit on any error + +# Configuration +CONTAINER_NAME="juice-shop" +HOST_IP="127.0.0.1" +HOST_PORT="3000" +BASE_URL="http://${HOST_IP}:${HOST_PORT}" + +echo "================================================" +echo "OWASP Juice Shop Verification Script" +echo "================================================" +echo "" + +# Check if container is running +echo "[1/6] Checking container status..." +if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + echo "ERROR: Container '${CONTAINER_NAME}' is not running" + echo " Run deployment first: bash labs/lab1-deploy.sh" + exit 1 +fi +echo "Container is running" +echo "" + +# Get container information +echo "[2/6] Container Information:" +echo "----------------------------------------" +docker ps --filter "name=${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" +echo "" + +# Check container logs for errors +echo "[3/6] Checking container logs..." +LOG_ERRORS=$(docker logs "${CONTAINER_NAME}" 2>&1 | grep -i "error" | head -n 5 || echo "No errors found") +if [ "$LOG_ERRORS" == "No errors found" ]; then + echo "No critical errors in logs" +else + echo "Found errors in logs:" + echo "$LOG_ERRORS" +fi +echo "" + +# Test HTTP connectivity +echo "[4/6] Testing HTTP connectivity..." +if command -v curl &> /dev/null; then + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${BASE_URL}" || echo "000") + if [ "$HTTP_STATUS" == "200" ]; then + echo "HTTP connection successful (Status: ${HTTP_STATUS})" + else + echo "HTTP Status: ${HTTP_STATUS}" + fi +else + echo "curl not found - skipping HTTP test" +fi +echo "" + +# Test API endpoint +echo "[5/6] Testing API endpoint (/rest/products)..." +echo "----------------------------------------" +if command -v curl &> /dev/null; then + echo "API Response (first 10 lines):" + echo "" + curl -s "${BASE_URL}/rest/products" | head -n 10 + echo "" + echo "----------------------------------------" + echo "API endpoint responding" + echo "" + echo "TIP: Copy the above API output to your triage report" +else + echo "curl not found - skipping API test" + echo " You can manually test: ${BASE_URL}/rest/products" +fi +echo "" + +# Check security headers +echo "[6/6] Checking security headers..." +echo "----------------------------------------" +if command -v curl &> /dev/null; then + echo "HTTP Headers:" + echo "" + curl -I -s "${BASE_URL}" | grep -E "(Server|X-|Content-Security-Policy|Strict-Transport-Security)" || echo "No security headers found" + echo "" + echo "----------------------------------------" + + # Analyze security headers + echo "" + echo "Security Header Analysis:" + HEADERS=$(curl -I -s "${BASE_URL}") + + if echo "$HEADERS" | grep -qi "Content-Security-Policy"; then + echo " CSP (Content Security Policy): Present" + else + echo " CSP (Content Security Policy): Missing" + fi + + if echo "$HEADERS" | grep -qi "Strict-Transport-Security"; then + echo " HSTS (HTTP Strict Transport Security): Present" + else + echo " HSTS (HTTP Strict Transport Security): Missing" + fi + + if echo "$HEADERS" | grep -qi "X-Frame-Options"; then + echo " X-Frame-Options: Present" + else + echo " X-Frame-Options: Missing" + fi + + if echo "$HEADERS" | grep -qi "X-Content-Type-Options"; then + echo " X-Content-Type-Options: Present" + else + echo " X-Content-Type-Options: Missing" + fi +else + echo "curl not found - skipping header check" +fi +echo "" + +# Summary +echo "================================================" +echo "Verification Complete!" +echo "================================================" +echo "" +echo "Summary:" +echo " • Container Status: Running" +echo " • Web Interface: ${BASE_URL}" +echo " • API Endpoint: ${BASE_URL}/rest/products" +echo "" diff --git a/labs/lab2/baseline/data-asset-diagram.png b/labs/lab2/baseline/data-asset-diagram.png new file mode 100644 index 00000000..4457d768 Binary files /dev/null and b/labs/lab2/baseline/data-asset-diagram.png differ diff --git a/labs/lab2/baseline/data-flow-diagram.png b/labs/lab2/baseline/data-flow-diagram.png new file mode 100644 index 00000000..a8803816 Binary files /dev/null and b/labs/lab2/baseline/data-flow-diagram.png differ diff --git a/labs/lab2/baseline/report.pdf b/labs/lab2/baseline/report.pdf new file mode 100644 index 00000000..0b55b83e Binary files /dev/null and b/labs/lab2/baseline/report.pdf differ diff --git a/labs/lab2/baseline/risks.json b/labs/lab2/baseline/risks.json new file mode 100644 index 00000000..c533cb1d --- /dev/null +++ b/labs/lab2/baseline/risks.json @@ -0,0 +1 @@ +[{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@juice-shop","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@reverse-proxy","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@user-browser","most_relevant_data_asset":"","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"container-baseimage-backdooring","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eContainer Base Image Backdooring\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"container-baseimage-backdooring@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"probable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-vault","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Vault (Secret Storage)\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-vault@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"missing-identity-store","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Identity Store\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eReverse Proxy\u003c/b\u003e as an example)","synthetic_id":"missing-identity-store@reverse-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@user-browser\u003edirect-to-app-no-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-hardening@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"missing-hardening@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"unencrypted-communication","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"high","title":"\u003cb\u003eUnencrypted Communication\u003c/b\u003e named \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e between \u003cb\u003eUser Browser\u003c/b\u003e and \u003cb\u003eJuice Shop Application\u003c/b\u003e transferring authentication data (like credentials, token, session-id, etc.)","synthetic_id":"unencrypted-communication@user-browser\u003edirect-to-app-no-proxy@user-browser@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"unencrypted-communication","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eUnencrypted Communication\u003c/b\u003e named \u003cb\u003eTo App\u003c/b\u003e between \u003cb\u003eReverse Proxy\u003c/b\u003e and \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unencrypted-communication@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e server-side web-requesting the target \u003cb\u003eWebhook Endpoint\u003c/b\u003e via \u003cb\u003eTo Challenge WebHook\u003c/b\u003e","synthetic_id":"server-side-request-forgery@juice-shop@webhook-endpoint@juice-shop\u003eto-challenge-webhook","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"juice-shop\u003eto-challenge-webhook","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eReverse Proxy\u003c/b\u003e server-side web-requesting the target \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e","synthetic_id":"server-side-request-forgery@reverse-proxy@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["reverse-proxy"]},{"category":"missing-waf","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eMissing Web Application Firewall (WAF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-waf@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"unencrypted-asset","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eUnencrypted Technical Asset\u003c/b\u003e named \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unencrypted-asset@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"unencrypted-asset","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eUnencrypted Technical Asset\u003c/b\u003e named \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"unencrypted-asset@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"missing-authentication","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@user-browser\u003edirect-to-app-no-proxy@user-browser@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e forwarded via \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-scripting","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eCross-Site Scripting (XSS)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"cross-site-scripting@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"missing-build-infrastructure","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Build Infrastructure\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-build-infrastructure@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]}] \ No newline at end of file diff --git a/labs/lab2/baseline/stats.json b/labs/lab2/baseline/stats.json new file mode 100644 index 00000000..88cd78be --- /dev/null +++ b/labs/lab2/baseline/stats.json @@ -0,0 +1 @@ +{"risks":{"critical":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"elevated":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":4},"high":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"low":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":5},"medium":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":14}}} \ No newline at end of file diff --git a/labs/lab2/baseline/technical-assets.json b/labs/lab2/baseline/technical-assets.json new file mode 100644 index 00000000..45457f1e --- /dev/null +++ b/labs/lab2/baseline/technical-assets.json @@ -0,0 +1 @@ +{"juice-shop":{"Id":"juice-shop","Title":"Juice Shop Application","Description":"OWASP Juice Shop server (Node.js/Express, v19.0.0).","Usage":0,"Type":1,"Size":2,"Technology":6,"Machine":2,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":true,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"In-scope web application (contains all business logic and vulnerabilities by design).","Tags":["app","nodejs"],"DataAssetsProcessed":["user-accounts","orders","product-catalog","tokens-sessions"],"DataAssetsStored":["logs"],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"juice-shop\u003eto-challenge-webhook","SourceId":"juice-shop","TargetId":"webhook-endpoint","Title":"To Challenge WebHook","Description":"Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved.","Protocol":2,"Tags":["egress"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["orders"],"DataAssetsReceived":null,"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":70.02881844380403},"persistent-storage":{"Id":"persistent-storage","Title":"Persistent Storage","Description":"Host-mounted volume for database, file uploads, and logs.","Usage":1,"Type":2,"Size":3,"Technology":10,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs).","Tags":["storage","volume"],"DataAssetsProcessed":[],"DataAssetsStored":["logs","user-accounts","orders","product-catalog"],"DataFormatsAccepted":[3],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":100},"reverse-proxy":{"Id":"reverse-proxy","Title":"Reverse Proxy","Description":"Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers.","Usage":0,"Type":1,"Size":2,"Technology":20,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Not exposed to internet directly; improves security of inbound traffic.","Tags":["optional","proxy"],"DataAssetsProcessed":["product-catalog","tokens-sessions"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"reverse-proxy\u003eto-app","SourceId":"reverse-proxy","TargetId":"juice-shop","Title":"To App","Description":"Proxy forwarding to app (HTTP on 3000 internally).","Protocol":1,"Tags":[],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":9.623538157950035},"user-browser":{"Id":"user-browser","Title":"User Browser","Description":"End-user web browser (client).","Usage":0,"Type":0,"Size":0,"Technology":2,"Machine":1,"Internet":true,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":true,"Encryption":0,"JustificationOutOfScope":"","Owner":"External User","Confidentiality":0,"Integrity":1,"Availability":1,"JustificationCiaRating":"Client controlled by end user (potentially an attacker).","Tags":["actor","user"],"DataAssetsProcessed":[],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"user-browser\u003eto-reverse-proxy-preferred","SourceId":"user-browser","TargetId":"reverse-proxy","Title":"To Reverse Proxy (preferred)","Description":"User browser to reverse proxy (HTTPS on 443).","Protocol":2,"Tags":["primary"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true},{"Id":"user-browser\u003edirect-to-app-no-proxy","SourceId":"user-browser","TargetId":"juice-shop","Title":"Direct to App (no proxy)","Description":"Direct browser access to app (HTTP on 3000).","Protocol":1,"Tags":["direct"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":25.859639506459924},"webhook-endpoint":{"Id":"webhook-endpoint","Title":"Webhook Endpoint","Description":"External WebHook service (3rd-party, if configured for integrations).","Usage":0,"Type":0,"Size":0,"Technology":14,"Machine":1,"Internet":true,"MultiTenant":true,"Redundant":true,"CustomDevelopedParts":false,"OutOfScope":true,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"Third-party service to receive notifications (not under our control).","Owner":"Third-Party","Confidentiality":1,"Integrity":1,"Availability":1,"JustificationCiaRating":"External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured.","Tags":["saas","webhook"],"DataAssetsProcessed":["orders"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":1}} \ No newline at end of file diff --git a/labs/lab2/secure/data-asset-diagram.png b/labs/lab2/secure/data-asset-diagram.png new file mode 100644 index 00000000..aacf4016 Binary files /dev/null and b/labs/lab2/secure/data-asset-diagram.png differ diff --git a/labs/lab2/secure/data-flow-diagram.png b/labs/lab2/secure/data-flow-diagram.png new file mode 100644 index 00000000..5ead09e2 Binary files /dev/null and b/labs/lab2/secure/data-flow-diagram.png differ diff --git a/labs/lab2/secure/report.pdf b/labs/lab2/secure/report.pdf new file mode 100644 index 00000000..db7c168a Binary files /dev/null and b/labs/lab2/secure/report.pdf differ diff --git a/labs/lab2/secure/risks.json b/labs/lab2/secure/risks.json new file mode 100644 index 00000000..13f39cbe --- /dev/null +++ b/labs/lab2/secure/risks.json @@ -0,0 +1 @@ +[{"category":"missing-authentication","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@user-browser\u003edirect-to-app-no-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-identity-store","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Identity Store\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eReverse Proxy\u003c/b\u003e as an example)","synthetic_id":"missing-identity-store@reverse-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@user-browser\u003edirect-to-app-no-proxy@user-browser@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e forwarded via \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@user-browser","most_relevant_data_asset":"","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"cross-site-scripting","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eCross-Site Scripting (XSS)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"cross-site-scripting@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"container-baseimage-backdooring","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eContainer Base Image Backdooring\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"container-baseimage-backdooring@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"probable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-vault","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Vault (Secret Storage)\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-vault@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"missing-waf","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eMissing Web Application Firewall (WAF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-waf@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@juice-shop","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@reverse-proxy","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"unencrypted-asset","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eUnencrypted Technical Asset\u003c/b\u003e named \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unencrypted-asset@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e server-side web-requesting the target \u003cb\u003eWebhook Endpoint\u003c/b\u003e via \u003cb\u003eTo Challenge WebHook\u003c/b\u003e","synthetic_id":"server-side-request-forgery@juice-shop@webhook-endpoint@juice-shop\u003eto-challenge-webhook","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"juice-shop\u003eto-challenge-webhook","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eReverse Proxy\u003c/b\u003e server-side web-requesting the target \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e","synthetic_id":"server-side-request-forgery@reverse-proxy@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["reverse-proxy"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-hardening@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"missing-hardening@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"missing-build-infrastructure","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Build Infrastructure\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-build-infrastructure@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]}] \ No newline at end of file diff --git a/labs/lab2/secure/stats.json b/labs/lab2/secure/stats.json new file mode 100644 index 00000000..c19a18a6 --- /dev/null +++ b/labs/lab2/secure/stats.json @@ -0,0 +1 @@ +{"risks":{"critical":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"elevated":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":2},"high":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"low":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":5},"medium":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":13}}} \ No newline at end of file diff --git a/labs/lab2/secure/technical-assets.json b/labs/lab2/secure/technical-assets.json new file mode 100644 index 00000000..2308062a --- /dev/null +++ b/labs/lab2/secure/technical-assets.json @@ -0,0 +1 @@ +{"juice-shop":{"Id":"juice-shop","Title":"Juice Shop Application","Description":"OWASP Juice Shop server (Node.js/Express, v19.0.0).","Usage":0,"Type":1,"Size":2,"Technology":6,"Machine":2,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":true,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"In-scope web application (contains all business logic and vulnerabilities by design).","Tags":["app","nodejs"],"DataAssetsProcessed":["user-accounts","orders","product-catalog","tokens-sessions"],"DataAssetsStored":["logs"],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"juice-shop\u003eto-challenge-webhook","SourceId":"juice-shop","TargetId":"webhook-endpoint","Title":"To Challenge WebHook","Description":"Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved.","Protocol":2,"Tags":["egress"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["orders"],"DataAssetsReceived":null,"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":70.02881844380403},"persistent-storage":{"Id":"persistent-storage","Title":"Persistent Storage","Description":"Host-mounted volume for database, file uploads, and logs.","Usage":1,"Type":2,"Size":3,"Technology":10,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs).","Tags":["storage","volume"],"DataAssetsProcessed":[],"DataAssetsStored":["logs","user-accounts","orders","product-catalog"],"DataFormatsAccepted":[3],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":100},"reverse-proxy":{"Id":"reverse-proxy","Title":"Reverse Proxy","Description":"Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers.","Usage":0,"Type":1,"Size":2,"Technology":20,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Not exposed to internet directly; improves security of inbound traffic.","Tags":["optional","proxy"],"DataAssetsProcessed":["product-catalog","tokens-sessions"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"reverse-proxy\u003eto-app","SourceId":"reverse-proxy","TargetId":"juice-shop","Title":"To App","Description":"Proxy forwarding to app (HTTPS on 3000 internally).","Protocol":2,"Tags":[],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":9.623538157950035},"user-browser":{"Id":"user-browser","Title":"User Browser","Description":"End-user web browser (client).","Usage":0,"Type":0,"Size":0,"Technology":2,"Machine":1,"Internet":true,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":true,"Encryption":0,"JustificationOutOfScope":"","Owner":"External User","Confidentiality":0,"Integrity":1,"Availability":1,"JustificationCiaRating":"Client controlled by end user (potentially an attacker).","Tags":["actor","user"],"DataAssetsProcessed":[],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"user-browser\u003eto-reverse-proxy-preferred","SourceId":"user-browser","TargetId":"reverse-proxy","Title":"To Reverse Proxy (preferred)","Description":"User browser to reverse proxy (HTTPS on 443).","Protocol":2,"Tags":["primary"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true},{"Id":"user-browser\u003edirect-to-app-no-proxy","SourceId":"user-browser","TargetId":"juice-shop","Title":"Direct to App (no proxy)","Description":"Direct browser access to app (HTTPS on 3000).","Protocol":2,"Tags":["direct"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":25.859639506459924},"webhook-endpoint":{"Id":"webhook-endpoint","Title":"Webhook Endpoint","Description":"External WebHook service (3rd-party, if configured for integrations).","Usage":0,"Type":0,"Size":0,"Technology":14,"Machine":1,"Internet":true,"MultiTenant":true,"Redundant":true,"CustomDevelopedParts":false,"OutOfScope":true,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"Third-party service to receive notifications (not under our control).","Owner":"Third-Party","Confidentiality":1,"Integrity":1,"Availability":1,"JustificationCiaRating":"External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured.","Tags":["saas","webhook"],"DataAssetsProcessed":["orders"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":1}} \ No newline at end of file diff --git a/labs/lab2/threagile-model.secure.yaml b/labs/lab2/threagile-model.secure.yaml new file mode 100644 index 00000000..49e04b46 --- /dev/null +++ b/labs/lab2/threagile-model.secure.yaml @@ -0,0 +1,416 @@ +threagile_version: 1.0.0 + +title: OWASP Juice Shop — Local Lab Threat Model +date: 2025-09-18 + +author: + name: Ilsaf Abdulkhakov + +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: + +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: none + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + + Juice Shop Application: + id: juice-shop + description: "OWASP Juice Shop server (Node.js/Express, v19.0.0)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: web-server + tags: ["app", "nodejs"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "In-scope web application (contains all business logic and vulnerabilities by design)." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - user-accounts + - orders + - product-catalog + - tokens-sessions + data_assets_stored: + - logs + data_formats_accepted: + - json + communication_links: + To Challenge WebHook: + target: webhook-endpoint + description: "Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved." + protocol: https + authentication: none + authorization: none + tags: ["egress"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - orders + + Persistent Storage: + id: persistent-storage + description: "Host-mounted volume for database, file uploads, and logs." + type: datastore + usage: devops + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: file-server + tags: ["storage", "volume"] + internet: false + machine: virtual + encryption: transparent + 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 + +individual_risk_categories: {} + +risk_tracking: {} + diff --git a/labs/lab2/threagile-model.yaml b/labs/lab2/threagile-model.yaml index 85c01a79..b24c0cd9 100644 --- a/labs/lab2/threagile-model.yaml +++ b/labs/lab2/threagile-model.yaml @@ -4,8 +4,7 @@ title: OWASP Juice Shop — Local Lab Threat Model date: 2025-09-18 author: - name: Student Name - homepage: https://example.edu + name: Ilsaf Abdulkhakov management_summary_comment: > Threat model for a local OWASP Juice Shop setup. Users access the app @@ -22,7 +21,6 @@ business_overview: 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: > @@ -411,19 +409,7 @@ shared_runtimes: 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 +risk_tracking: {} \ No newline at end of file diff --git a/labs/screenshots/juice-shop.png b/labs/screenshots/juice-shop.png new file mode 100644 index 00000000..ab6bd3b6 Binary files /dev/null and b/labs/screenshots/juice-shop.png differ diff --git a/labs/screenshots/pr-template-verification.png b/labs/screenshots/pr-template-verification.png new file mode 100644 index 00000000..0f4c4273 Binary files /dev/null and b/labs/screenshots/pr-template-verification.png differ diff --git a/labs/submission1.md b/labs/submission1.md new file mode 100644 index 00000000..b1ce6238 --- /dev/null +++ b/labs/submission1.md @@ -0,0 +1,80 @@ +# Lab 1 Submission — OWASP Juice Shop Setup & PR Workflow + +**Student:** Ilsaf Abdulkhakov +**Date:** Feb 8, 2026 +**Lab:** Lab 1 — Setup OWASP Juice Shop & PR Workflow + +--- + +## Task 1 — OWASP Juice Shop Deployment & Triage Report + +### Triage Report — OWASP Juice Shop + +#### Scope & Asset +- **Asset:** OWASP Juice Shop (local lab instance) +- **Image:** `bkimminich/juice-shop:v19.0.0` +- **Release link/date:** [v19.0.0](https://github.com/juice-shop/juice-shop/releases/tag/v19.0.0) — Sep 4, 2025 +- **Image digest:** `sha256:2765a26de7647609099a338d5b7f61085d95903c8703bb70f03fcc4b12f0818d` + +#### Environment +- **Host OS:** macOS 26.2 +- **Docker:** 28.0.4 + +#### Deployment Details +- **Run command used:** `docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v19.0.0` +- **Access URL:** http://127.0.0.1:3000 +- **Network exposure:** 127.0.0.1 only [x] Yes [ ] No + +#### Health Check +- **Page load:** +  + +- **API check:** + ```json + +
+ +