Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Goal

<! What this PR delivers in one sentence. >

## Changes

<! List the files/artifacts added or modified. >

-

## Testing

<! Describe how you verified the work. Include commands and observed output. >

-

## Artifacts & Screenshots

<! Link to files in this PR or embed screenshots where useful. >

-

## Checklist

- [ ] Title is clear (`feat(labN): <topic>` style)
- [ ] No secrets/large temp files committed
- [ ] Submission file at `submissions/labN.md` exists
45 changes: 45 additions & 0 deletions .github/workflows/lab1-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Lab 1 Smoke Test

on:
pull_request:
branches:
- main

permissions:
contents: read

jobs:
smoke-test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Run OWASP 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 become healthy
run: |
for i in $(seq 1 30); do
if curl --silent --fail http://127.0.0.1:3000/rest/admin/application-version; then
echo
echo "Juice Shop version endpoint is healthy"
exit 0
fi

echo "Waiting for Juice Shop... attempt $i/30"
sleep 2
done

echo "Juice Shop did not become healthy within 60 seconds"
docker logs juice-shop
exit 1

- name: Verify homepage returns HTTP 200
run: |
curl --silent --fail --show-error http://127.0.0.1:3000 > /dev/null
echo "Homepage returned HTTP 200"
115 changes: 115 additions & 0 deletions submissions/lab1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# 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:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0`
* Host OS: Arch Linux, Linux 7.0.10-arch1-1, x86_64
* Docker version: 29.5.2

### 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 — Yes
* Container restart policy: No
* Container ID: `c9c3a6b9fff6`
* Container status: `Up 24 minutes`
* Port mapping: `127.0.0.1:3000->3000/tcp`

### Health Check

* HTTP code on `/`: `200`
* Application version: `{"version":"20.0.0"}`
* Product count: `46`
* Docker status:

```text
c9c3a6b9fff6 bkimminich/juice-shop:v20.0.0 "/nodejs/bin/node /j…" 24 minutes ago Up 24 minutes 127.0.0.1:3000->3000/tcp juice-shop
```

### Initial Surface Snapshot (from browser exploration)

* Login/Registration visible: Yes
* Product listing/search present: Yes
* Admin or account area discoverable: Yes
* Client-side errors in DevTools console: No
* Pre-populated local storage / cookies: Before authentication, Local Storage for `http://127.0.0.1:3000` was empty. Cookies were present: `continueCode`, `language=en`, and `welcomebanner_status=dismiss`. After registration/login, a `token` value appeared in both Local Storage and Cookies; the token value was redacted because it is an authentication token.
* Network/API surface: Product and review API requests were visible in the browser Network tab during normal browsing.

### Security Headers (Quick Look)

Run:

```bash
curl -sI http://127.0.0.1:3000 | head -20
```

Observed response:

```text
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: Thu, 10 Sep 2026 10:27:35 GMT
ETag: W/"26af-1a08adbcadf"
Content-Type: text/html; charset=UTF-8
Content-Length: 9903
Vary: Accept-Encoding
Date: Thu, 10 Sep 2026 10:34:17 GMT
Connection: keep-alive
Keep-Alive: timeout=5
```

Which of these are MISSING?

* [x] `Content-Security-Policy`
* [x] `Strict-Transport-Security`
* [ ] `X-Content-Type-Options: nosniff`
* [ ] `X-Frame-Options: SAMEORIGIN`

Missing security headers are mapped to OWASP Top 10:2025 **A02 — Security Misconfiguration**.

### Top 3 Risks Observed

1. **Authentication token stored client-side** — After registration/login, an authentication token appeared in both Local Storage and Cookies. This makes client-side token storage part of the application's security surface and should be reviewed for token protection, lifetime, and handling. This maps to OWASP Top 10:2025 **A07 — Authentication Failures**.

2. **Missing security headers** — The initial HTTP response does not include `Content-Security-Policy` or `Strict-Transport-Security`. This represents a security configuration issue and reduces the browser-level security controls applied to the application. This maps to OWASP Top 10:2025 **A02 — Security Misconfiguration**.

3. **Public product and review API surface** — Product and review API endpoints are visible in the browser Network tab during normal browsing. Their authorization boundaries should be tested to determine whether users can access or modify resources they should not be allowed to access. This maps to OWASP Top 10:2025 **A01 — Broken Access Control**.


## PR Template Setup

- File: `.github/PULL_REQUEST_TEMPLATE.md`
- Sections included: Goal / Changes / Testing / Artifacts & Screenshots
- Checklist items:
- Title is clear (`feat(labN): <topic>` style)
- No secrets/large temp files committed
- Submission file at `submissions/labN.md` exists
- Auto-fill verified: [ ] No — the template file exists at `.github/PULL_REQUEST_TEMPLATE.md`, but it did not auto-fill for the first PR because this PR introduces the template itself. The PR body was filled manually using the same template structure.

## GitHub Community

Starring repositories matters in open source because it helps make useful projects more visible and also lets me quickly find them later. Following developers is useful for team projects and professional growth because it helps me track their public work, learn from their activity, and stay connected with people from the course.

## Bonus: CI Smoke Test

- Workflow file: `.github/workflows/lab1-smoke.yml`
- Trigger: `pull_request` on `main`
- Run URL (must be green): https://github.com/Troshkins/DevSecOps-Intro/actions/runs/27350872180
- Workflow run duration: 21s
- Curl response excerpt:
Waiting for Juice Shop... attempt 1/30
{"version":"20.0.0"}
Juice Shop version endpoint is healthy
0s
Homepage returned HTTP 200