From 523222a0e10789f59d44d9592ffac7a8581ee475 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 12 Jun 2026 19:04:16 +0300 Subject: [PATCH 1/2] feat(lab1): juice shop deploy + PR template + triage report --- .github/PULL_REQUEST_TEMPLATE.md | 25 ++++++++ .github/workflows/lab1-smoke.yml | 70 +++++++++++++++++++++ submissions/lab1.md | 103 +++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/lab1-smoke.yml create mode 100644 submissions/lab1.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..9129b45af --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +## Goal + + +## Changes + +- + +## Testing + +``` +# Example: +docker ps --filter name=juice-shop +curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000 +``` + +## Artifacts & Screenshots + +- `submissions/labN.md` + +--- + +## Checklist +- [ ] Title follows `feat(labN): ` style +- [ ] No secrets or large temp files committed +- [ ] Submission file exists at `submissions/labN.md` diff --git a/.github/workflows/lab1-smoke.yml b/.github/workflows/lab1-smoke.yml new file mode 100644 index 000000000..fce4880ae --- /dev/null +++ b/.github/workflows/lab1-smoke.yml @@ -0,0 +1,70 @@ +name: lab1-smoke + +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + smoke-test: + name: Juice Shop smoke test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Pull and start Juice Shop + run: | + docker run -d --name juice-shop \ + -p 127.0.0.1:3000:3000 \ + bkimminich/juice-shop:v20.0.0 + + - name: Wait for Juice Shop to be ready (max 60s) + run: | + echo "Waiting for Juice Shop to start..." + for i in $(seq 1 30); do + if curl --silent --fail http://localhost:3000/rest/admin/application-version > /dev/null; then + echo "Juice Shop is up after $((i * 2))s" + exit 0 + fi + echo "Attempt $i/30 — not ready yet, sleeping 2s..." + sleep 2 + done + echo "ERROR: Juice Shop did not start within 60 seconds" + docker logs juice-shop + exit 1 + + - name: Verify homepage returns HTTP 200 + run: | + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000) + echo "Homepage HTTP status: $HTTP_CODE" + if [ "$HTTP_CODE" != "200" ]; then + echo "ERROR: Expected 200, got $HTTP_CODE" + exit 1 + fi + echo "HTTP 200 confirmed — smoke test passed." + + - name: Verify version endpoint + run: | + RESPONSE=$(curl -s http://localhost:3000/rest/admin/application-version) + echo "Version endpoint response: $RESPONSE" + echo "$RESPONSE" | grep -q '"version":"20.0.0"' || (echo "ERROR: unexpected version response" && exit 1) + echo "Version check passed." + + - name: Verify product count + run: | + COUNT=$(curl -s http://localhost:3000/api/Products | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['data']))") + echo "Product count: $COUNT" + if [ "$COUNT" -lt 1 ]; then + echo "ERROR: No products returned" + exit 1 + fi + echo "Product count check passed: $COUNT products found." + + - name: Cleanup + if: always() + run: docker rm -f juice-shop || true diff --git a/submissions/lab1.md b/submissions/lab1.md new file mode 100644 index 000000000..1240adf42 --- /dev/null +++ b/submissions/lab1.md @@ -0,0 +1,103 @@ +k# Lab 1 — Submission + +## Triage Report: OWASP Juice Shop + +### Scope & Asset +- Asset: OWASP Juice Shop (local lab instance) +- Image: `bkimminich/juice-shop:v20.0.0` +- Image digest: `sha256:99779f57113bd47312e8fe7b264ff402ee41da76ddda7f2fc842a92ad51827ce` +- Host OS: Kali Linux (rolling) +- Docker version: 28.5.2+dfsg4, build 9cc6dea35e9a963f281434761c656fba4ac43aed + +### Deployment Details +- Run command used: `docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v20.0.0` +- Access URL: http://127.0.0.1:3000 +- Network exposure: 127.0.0.1 only? [x] Yes +- Container restart policy: default (`no`) + +### Health Check +- HTTP code on `/`: 200 +- API check (first 200 chars of `/api/Products`): + ``` + {"status":"success","data":[{"id":1,"name":"Apple Juice (1000ml)","description":"The all-time classic.","price":1.99,"deluxePrice":0.99,"image":"apple_juice.jpg","createdAt":"2026-06-12T15:40:48.909Z" + ``` +- Container uptime: `juice-shop Up 9 minutes 127.0.0.1:3000->3000/tcp` + +### Initial Surface Snapshot (from browser exploration) +- Login/Registration visible: [x] Yes — Account menu (top-right) contains Login and Register forms accessible without authentication +- Product listing/search present: [x] Yes — 46 products returned via `/api/Products`; search bar functional on main page +- Admin or account area discoverable: [x] Yes — `/#/administration` accessible after login; `/rest/admin/application-version` returns version info with no auth required +- Client-side errors in DevTools console: [x] Yes — Angular routing errors observed on navigation to undefined paths +- Pre-populated local storage / cookies: No pre-populated items on first load; `cookieconsent_status` cookie written after cookie banner interaction; `welcomeBannerStatus` key added to localStorage on dismiss + +### Security Headers (Quick Look) +``` +HTTP/1.1 200 OK +Access-Control-Allow-Origin: * +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +Feature-Policy: payment 'self' +X-Recruiting: /#/jobs +Accept-Ranges: bytes +Cache-Control: public, max-age=0 +Last-Modified: Fri, 12 Jun 2026 15:40:51 GMT +Content-Type: text/html; charset=UTF-8 +Content-Length: 9903 +Date: Fri, 12 Jun 2026 15:50:24 GMT +Connection: keep-alive +``` + +Which of these are MISSING? (cross-reference Lecture 1 OWASP Top 10:2025 — A06) +- [x] `Content-Security-Policy` — **MISSING**: no CSP header present, allowing unrestricted inline scripts and external resource loading +- [x] `Strict-Transport-Security` — **MISSING**: application runs over plain HTTP with no HSTS enforcement +- [ ] `X-Content-Type-Options: nosniff` — **present** +- [ ] `X-Frame-Options` — **present** (SAMEORIGIN) + +### Top 3 Risks Observed + +1. **Broken Access Control (A01:2025)** — The `/rest/admin/application-version` endpoint returns exact version information to any unauthenticated caller. This gives an attacker precise target intelligence to look up known CVEs for that specific release without needing any credentials, directly lowering the cost of exploitation. + +2. **Security Misconfiguration (A05:2025)** — The `Access-Control-Allow-Origin: *` response header permits any web origin to read API responses via cross-origin requests. Combined with the absent `Content-Security-Policy`, a malicious page could silently exfiltrate product data, user sessions, or other API responses from a victim's browser session. + +3. **Injection (A03:2025)** — The product search endpoint (`/rest/products/search?q=`) passes user input directly into SQL queries without sanitisation, making it vulnerable to SQL injection. A successful exploit could allow an attacker to read, modify, or delete any data in the underlying SQLite database, including user credentials and order history. + +--- + +## PR Template Setup + +- File: `.github/PULL_REQUEST_TEMPLATE.md` +- Sections included: Goal / Changes / Testing / Artifacts & Screenshots +- Checklist items: + - Title follows `feat(labN): ` convention + - No secrets or large temp files committed + - Submission file exists at `submissions/labN.md` +- Auto-fill verified: [ ] Yes — PR description showed the template automatically when the PR was opened from `feature/lab1` + +--- + +## GitHub Community + +Starring repositories signals to the maintainer that the project is useful and helps others discover quality tools through GitHub's trending and recommendation algorithms — it is the open-source equivalent of a citation. Following developers provides a live feed of their commits, new repositories, and activity, which is practical in team projects for staying aware of what colleagues are shipping and in professional growth for learning patterns and tooling from experienced engineers directly through their public work. + +Actions completed: +- [x] Starred the course repository (`DevSecOps-Intro`) +- [x] Starred `simple-container-com/api` +- [x] Following professor @Cre-eD +- [x] Following TA @Naghme98 +- [x] Following TA @pierrepicaud +- [x] Following 3+ classmates from the course + +--- + +## Bonus: CI Smoke Test + +- Workflow file: `.github/workflows/lab1-smoke.yml` +- Trigger: `pull_request` on `main` +- Run URL (must be green): *(link appears in Actions tab after PR is opened)* +- Workflow run duration: ~45s +- Curl response excerpt: + ``` + {"version":"20.0.0"} + HTTP 200 + Juice Shop is healthy — smoke test passed. + ``` From b13efb551afc6a14f827f084917472f3cb8cdfe8 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 12 Jun 2026 19:27:37 +0300 Subject: [PATCH 2/2] feat(lab1): triage report fix --- submissions/lab1.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/submissions/lab1.md b/submissions/lab1.md index 1240adf42..625d308bb 100644 --- a/submissions/lab1.md +++ b/submissions/lab1.md @@ -93,11 +93,10 @@ Actions completed: - Workflow file: `.github/workflows/lab1-smoke.yml` - Trigger: `pull_request` on `main` -- Run URL (must be green): *(link appears in Actions tab after PR is opened)* -- Workflow run duration: ~45s +- Run URL (must be green): https://github.com/Wilikson173/DevSecOps-Intro/actions/runs/27428430062/job/81072211251 +- Workflow run duration: ~23s - Curl response excerpt: ``` - {"version":"20.0.0"} - HTTP 200 - Juice Shop is healthy — smoke test passed. + Homepage HTTP status: 200 + HTTP 200 confirmed — smoke test passed. ```