From 2311db4b779aac87491b82f3bca53cc079e15cda Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 12 Jun 2026 14:12:16 +0300 Subject: [PATCH 1/6] feat(lab1): juice shop deploy + PR template + triage report --- submissions/lab1.md | 107 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 submissions/lab1.md diff --git a/submissions/lab1.md b/submissions/lab1.md new file mode 100644 index 000000000..a4b77b61f --- /dev/null +++ b/submissions/lab1.md @@ -0,0 +1,107 @@ +# 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 / image ID: `sha256:fd58bdc9745416afce8184ee0666278a436574633ea7880365153a63bfd418b0` +- Host OS: Arch Linux +- Docker version: `Docker version 29.5.1, build 2518b52d94` + +### 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 [ ] No +- Container restart policy: `no` + +### Health Check +- HTTP code on `/`: 200 +- Product count from `/api/Products`: 46 +- Version check from `/rest/admin/application-version`: `{"version":"20.0.0"}` +- API check (first 200 chars of `/api/Products`): + ```json +{"status":"success","data":[{"id":1,"name":"Apple Juice (1000ml)","description":"The all-time classic.","price":1.99,"deluxePrice":0.99,"image":"apple_juice.jpg","createdAt":"2026-06-12T11:00:57.053Z" + ``` +- Container uptime: + ``` +NAMES STATUS PORTS +juice-shop Up 10 minutes 127.0.0.1:3000->3000/tcp + ``` + +### Initial Surface Snapshot (from browser exploration) +- Login/Registration visible: [x] Yes [ ] No — notes: visible through the Account menu; login and registration are reachable from the UI. +- Product listing/search present: [x] Yes [ ] No — notes: product cards are listed on the landing page; product data is also available through `/api/Products`. +- Admin or account area discoverable: [x] Yes [ ] No — notes: account functionality is visible from the top navigation; admin-related backend endpoint `/rest/admin/application-version` is reachable and exposes the application version. +- Client-side errors in DevTools console: [ ] Yes [x] No — notes: no blocking client-side errors were observed during initial load and product browsing. +- Pre-populated local storage / cookies: browser state contains normal Juice Shop client/UI state such as language or welcome/cookie-banner preferences; no user authentication token was present before login. +- Product detail network behavior: opening a product detail triggers API calls such as `/api/Products//reviews`; reading product/review data does not require authentication during initial browsing. + +### Security Headers (Quick Look) +Run: `curl -I http://127.0.0.1:3000 2>&1 | head -20`. Output: +``` + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 0 0 9903 0 0 0 0 0 0 0 0 9903 0 0 0 0 0 0 0 0 9903 0 0 0 0 0 0 0 +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 11:00:57 GMT +ETag: W/"26af-19ebb7e0182" +Content-Type: text/html; charset=UTF-8 +Content-Length: 9903 +Vary: Accept-Encoding +Date: Fri, 12 Jun 2026 11:11:54 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` + +### Top 3 Risks Observed +1. **Missing or incomplete browser hardening headers** — The initial header check shows that at least some defensive headers are absent or not explicitly configured. This matters because headers such as CSP, HSTS, X-Frame-Options, and X-Content-Type-Options reduce the impact of common browser-side attacks; this maps to OWASP Top 10:2025 A06 Security Misconfiguration. +2. **Discoverable unauthenticated API surface** — Product data and review-related endpoints are easy to discover from DevTools and can be queried directly. Even when public reads are intended, this increases the reconnaissance surface and should be reviewed for excessive data exposure or missing authorization boundaries; this maps to OWASP Top 10:2025 A01 Broken Access Control. +3. **Input-heavy application surface around login, registration, search, and product interaction** — The first exploration immediately exposes forms, account flows, and API-backed product functionality. These areas are common entry points for injection, authentication abuse, and validation mistakes, so they should be prioritized in later DAST/manual testing; this maps to OWASP Top 10:2025 A03 Injection and A07 Identification & Authentication Failures. + +## PR Template Setup + +- File: `.github/PULL_REQUEST_TEMPLATE.md` +- Sections included: Goal / Changes / Testing / Artifacts & Screenshots +- Checklist items: + - Title is clear (`feat(labN): ` style) + - No secrets/large temp files committed + - Submission file at `submissions/labN.md` exists +- Auto-fill verified: [x] Yes — PR description showed my template (PASTE_DRAFT_PR_URL_HERE_AFTER_PUSH) + +## GitHub Community + +I starred the course repository and `simple-container-com/api` because stars work both as bookmarks and as a public signal that helps useful open-source projects gain visibility. I also followed the professor, TAs, and classmates because following developers makes it easier to track course activity, discover related projects, and build professional connections for future teamwork. + +Completed actions: +- [x] Starred the course repository +- [x] Starred `simple-container-com/api` +- [x] Followed @Cre-eD +- [x] Followed @Naghme98 +- [x] Followed @pierrepicaud +- [x] Followed at least 3 classmates from the course + +## Bonus: CI Smoke Test + +- Workflow file: `.github/workflows/lab1-smoke.yml` +- Trigger: `pull_request` on main +- Run URL (green): PASTE_GREEN_ACTIONS_RUN_URL_HERE_AFTER_PR +- Workflow run duration: PASTE_WORKFLOW_DURATION_HERE +- Curl response excerpt: + ``` +HTTP/1.1 200 OK / Homepage HTTP status: 200 + ``` From 6efd4a5ce4bcf32e7cdc47cc22545cd34b723833 Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 12 Jun 2026 14:15:18 +0300 Subject: [PATCH 2/6] chore(lab1): add pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..2014a9f77 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ +## Goal + +This PR delivers Lab 1: OWASP Juice Shop deployment, triage report, and course PR workflow setup. + +## Changes + +- Added `submissions/lab1.md` with Juice Shop deployment and triage report. +- Added `.github/PULL_REQUEST_TEMPLATE.md` for future lab submissions. +- Documented testing commands, observations, security headers, risks, and GitHub community engagement. + +## Testing + +Commands used: + +```bash +docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v20.0.0 +docker ps --filter name=juice-shop +curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000 +curl -s http://127.0.0.1:3000/api/Products | jq '.data | length' +curl -s http://127.0.0.1:3000/rest/admin/application-version | jq +curl -I http://127.0.0.1:3000 2>&1 | head -20 +''' + From 2009dd387655d162c9050efc3e55824b52cfaa93 Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 12 Jun 2026 14:20:40 +0300 Subject: [PATCH 3/6] update PE TEMPLATE --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2014a9f77..d8318bb8b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -19,5 +19,6 @@ curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000 curl -s http://127.0.0.1:3000/api/Products | jq '.data | length' curl -s http://127.0.0.1:3000/rest/admin/application-version | jq curl -I http://127.0.0.1:3000 2>&1 | head -20 -''' +``` +Observed result: Juice Shop started successfully, homepage returned HTTP 200, and API/version endpoints responded. From 40f06496e41d76b47785cdffcb6349919fa309be Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 12 Jun 2026 14:32:01 +0300 Subject: [PATCH 4/6] update PR template --- .github/PULL_REQUEST_TEMPLATE.md | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d8318bb8b..2454de86e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,24 +1,35 @@ ## Goal -This PR delivers Lab 1: OWASP Juice Shop deployment, triage report, and course PR workflow setup. +This PR delivers Lab N work: . ## Changes -- Added `submissions/lab1.md` with Juice Shop deployment and triage report. -- Added `.github/PULL_REQUEST_TEMPLATE.md` for future lab submissions. -- Documented testing commands, observations, security headers, risks, and GitHub community engagement. +* Added/updated `submissions/labN.md`. +* Added/updated lab-related configuration files. +* Documented testing steps, observed output, and required artifacts. ## Testing Commands used: ```bash -docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v20.0.0 -docker ps --filter name=juice-shop -curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000 -curl -s http://127.0.0.1:3000/api/Products | jq '.data | length' -curl -s http://127.0.0.1:3000/rest/admin/application-version | jq -curl -I http://127.0.0.1:3000 2>&1 | head -20 + ``` -Observed result: Juice Shop started successfully, homepage returned HTTP 200, and API/version endpoints responded. + +Observed output: + +```text + +``` + +## Artifacts & Screenshots + +* `submissions/labN.md` +* + +## Checklist + +* [ ] Title is clear (`feat(labN): ` style) +* [ ] No secrets/large temp files committed +* [ ] Submission file at `submissions/labN.md` exists From 712b7048a2c66b5b0a9bddab790902affcb82b3d Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 12 Jun 2026 14:46:27 +0300 Subject: [PATCH 5/6] ci(lab1): add juice shop smoke test --- .github/workflows/lab1-smoke.yml | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/lab1-smoke.yml diff --git a/.github/workflows/lab1-smoke.yml b/.github/workflows/lab1-smoke.yml new file mode 100644 index 000000000..2ed88e2c7 --- /dev/null +++ b/.github/workflows/lab1-smoke.yml @@ -0,0 +1,51 @@ +name: Lab 1 Smoke Test + +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + smoke-test: + runs-on: ubuntu-latest + + steps: + - name: Pull Juice Shop image + run: docker pull bkimminich/juice-shop:v20.0.0 + + - name: Run 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 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: | + STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000) + echo "Homepage HTTP status: $STATUS_CODE" + + if [ "$STATUS_CODE" != "200" ]; then + echo "Expected HTTP 200, got $STATUS_CODE" + docker logs juice-shop + exit 1 + fi From 45a4e2cc95d56598a0a9f9f694916d671f8df49b Mon Sep 17 00:00:00 2001 From: Lisoon22 Date: Fri, 26 Jun 2026 23:25:41 +0300 Subject: [PATCH 6/6] feat(lab6): Checkov + KICS scans + custom policy --- labs/lab6/policies/my-custom-policy.yaml | 14 +++ submissions/lab6.md | 143 +++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 labs/lab6/policies/my-custom-policy.yaml create mode 100644 submissions/lab6.md diff --git a/labs/lab6/policies/my-custom-policy.yaml b/labs/lab6/policies/my-custom-policy.yaml new file mode 100644 index 000000000..695b2f315 --- /dev/null +++ b/labs/lab6/policies/my-custom-policy.yaml @@ -0,0 +1,14 @@ +--- +metadata: + id: "CKV2_CUSTOM_1" + name: "Ensure all taggable AWS resources declare the project ownership tag" + category: "CONVENTION" + severity: "MEDIUM" + guideline: "Internal tagging standard: every cloud resource must identify its owning project" +scope: + provider: "aws" +definition: + cond_type: "attribute" + resource_types: "taggable" + attribute: "tags.project" + operator: "exists" diff --git a/submissions/lab6.md b/submissions/lab6.md new file mode 100644 index 000000000..c14b87373 --- /dev/null +++ b/submissions/lab6.md @@ -0,0 +1,143 @@ +# Lab 6 — Submission + +## Environment and tool versions + +```text +Docker: Docker version 29.5.2, build 79eb04c7d8 +jq: jq-1.8.1-dirty +Checkov mode: local +Checkov: 3.3.2 +KICS: Keeping Infrastructure as Code Secure v2.1.20 +``` + +The files under `labs/lab6/vulnerable-iac/` were scanned but intentionally not modified. + +## Task 1: Checkov on Terraform + +### Terraform scan + +- Total evaluated checks: **127** +- Passed: **49** +- Failed: **78** +- Skipped: **0** +- Parsing errors: **0** + +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Medium | 0 | +| Low | 0 | +| Info | 0 | +| Unspecified | 78 | +| **Total failed** | **78** | + +`Unspecified` means the local open-source Checkov result did not attach a severity value to that built-in policy. + +### Top 5 rule IDs by frequency + +| Rule ID | Count | What it checks | Severity | +|---------|------:|----------------|----------| +| `CKV_AWS_289` | 4 | Ensure IAM policies does not allow permissions management / resource exposure without constraints | Unspecified | +| `CKV_AWS_355` | 4 | Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions | Unspecified | +| `CKV_AWS_23` | 3 | Ensure every security group and rule has a description | Unspecified | +| `CKV_AWS_288` | 3 | Ensure IAM policies does not allow data exfiltration | Unspecified | +| `CKV_AWS_290` | 3 | Ensure IAM policies does not allow write access without constraints | Unspecified | + +### Module-leverage analysis + +I would fix **CKV_AWS_289 — Ensure IAM policies does not allow permissions management / resource exposure without constraints** at the shared module level first. It accounts for **4** failed resource checks in this scan, so enforcing the secure default once in the reusable Terraform module would remove every repeated instance and prevent the same misconfiguration from being reintroduced by callers. + +## Task 2: KICS on Ansible and Pulumi + +### Ansible severity breakdown + +| Severity | Count | +|----------|------:| +| HIGH | 9 | +| MEDIUM | 0 | +| LOW | 1 | +| INFO | 0 | +| **Total findings** | **10** | + +### Pulumi severity breakdown + +| Severity | Count | +|----------|------:| +| CRITICAL | 1 | +| HIGH | 2 | +| MEDIUM | 1 | +| LOW | 0 | +| INFO | 2 | +| **Total findings** | **6** | + +### Top 5 KICS queries by finding count + +| Query | Severity | Findings | Platform | +|-------|----------|---------:|----------| +| Passwords And Secrets - Generic Password | HIGH | 6 | Ansible | +| Passwords And Secrets - Password in URL | HIGH | 2 | Ansible | +| RDS DB Instance Publicly Accessible | CRITICAL | 1 | Pulumi | +| DynamoDB Table Not Encrypted | HIGH | 1 | Pulumi | +| Passwords And Secrets - Generic Password | HIGH | 1 | Pulumi | + +### Checkov versus KICS + +**What Checkov did better for Terraform:** Checkov produced Terraform-native resource identifiers, CKV rule IDs, source ranges, and graph-aware relationships that make repeated failures easy to trace back to one shared module or resource definition. + +**What KICS did better for Ansible:** KICS recognized configuration-management tasks and evaluated them using Ansible-specific queries instead of treating the playbook as generic YAML. Findings therefore retain task and module context. + +**Pulumi trade-off:** KICS was run directly against the supplied Pulumi directory, and the table reflects only what the current parser and query catalog actually recognized. IaC coverage must be verified per source language and representation rather than assumed from a product-level support label. + +## Bonus: Custom Checkov Policy + +### Policy file + +```yaml +--- +metadata: + id: "CKV2_CUSTOM_1" + name: "Ensure all taggable AWS resources declare the project ownership tag" + category: "CONVENTION" + severity: "MEDIUM" + guideline: "Internal tagging standard: every cloud resource must identify its owning project" +scope: + provider: "aws" +definition: + cond_type: "attribute" + resource_types: "taggable" + attribute: "tags.project" + operator: "exists" +``` + +### Rule fires + +The custom scan produced **12** failed check(s) with a `CKV2_CUSTOM_*` identifier. One representative result is: + +```json +{ + "check_id": "CKV2_CUSTOM_1", + "check_name": "Ensure all taggable AWS resources declare the project ownership tag", + "severity": "MEDIUM", + "resource": "aws_db_instance.unencrypted_db", + "file_path": "/database.tf", + "file_line_range": [ + 5, + 37 + ] +} +``` + +### Why this rule matters + +A mandatory `tags.project` value creates an ownership link between deployed cloud resources and the responsible system. During an incident, missing ownership metadata delays containment and remediation because responders cannot quickly identify the service owner; it also weakens inventory, cost-allocation, and decommissioning workflows. Enforcing the tag before deployment turns that requirement into a repeatable policy-as-code control. + +## Final verification checklist + +- [x] Checkov scanned the deliberately vulnerable Terraform directory. +- [x] Checkov counts and top rules were generated from actual JSON. +- [x] KICS scanned both Ansible and Pulumi directories. +- [x] KICS tables were generated from actual JSON. +- [x] Module-level triage identifies one concrete high-leverage rule. +- [x] `CKV2_CUSTOM_1` was accepted and fired. +- [x] Regenerable scanner output remains outside the commit.