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
24 changes: 24 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Goal
<!-- 1 sentence: what this PR delivers -->

## Changes
<!-- Bullet list of artifacts added/modified -->
-
-
-

## Testing
<!-- Commands + observed output -->
```bash
# <command>
# <output>
```

## Artifacts & Screenshots
<!-- Links to files in this PR, image embeds where useful -->
-

## Checklist
- [ ] Title is clear (`feat(labN): <topic>` style)
- [ ] No secrets/large temp files committed
- [ ] Submission file at `submissions/labN.md` exists
49 changes: 49 additions & 0 deletions .github/workflows/lab1-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Lab 1 — Juice Shop 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: Pull and 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 be healthy
run: |
echo "Waiting for Juice Shop to start..."
for i in $(seq 1 30); do
if curl --silent --fail http://127.0.0.1:3000/rest/admin/application-version >/dev/null; then
echo "Juice Shop is up!"
exit 0
fi
echo "Attempt $i/30 — not ready yet, sleeping 2s..."
sleep 2
done
echo "Juice Shop failed to start within 60s"
docker logs juice-shop
exit 1

- name: Verify homepage returns HTTP 200
run: |
curl -I -s http://127.0.0.1:3000 | head -5
curl -s -o /dev/null -w "HTTP Status: %{http_code}\n" http://127.0.0.1:3000

- name: Verify product API
run: |
curl -s http://127.0.0.1:3000/api/Products | jq '.data | length'

- name: Verify version endpoint
run: |
curl -s http://127.0.0.1:3000/rest/admin/application-version | jq
36 changes: 36 additions & 0 deletions labs/lab9/falco/rules/custom-rules.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
- rule: Write to /tmp by container
desc: Detect successful file opens for writing below /tmp from inside a container
condition: >
open_write and
container.id != host and
fd.name startswith /tmp/
output: >
Write to /tmp by container
(container=%container.name user=%user.name file=%fd.name command=%proc.cmdline)
priority: WARNING
tags: [container, drift]
exceptions:
- name: allowed_package_manager_tmp_writes
fields: proc.name
comps: in
values: [apk]

- rule: Possible Cryptominer Activity
desc: Detect successful container connections to common mining-pool ports or known miner process execution
condition: >
container.id != host and
(
(
evt.type = connect and
evt.dir = < and
fd.sockfamily = ip and
fd.sport in (3333, 4444, 5555, 7777, 14444, 19999, 45700) and
(evt.rawres >= 0 or evt.res = EINPROGRESS)
) or
(spawned_process and proc.name in (xmrig, ethminer, cgminer, "t-rex", claymore))
)
output: >
Possible Cryptominer Activity
(container=%container.name process=%proc.name command=%proc.cmdline target=%fd.name server_ip=%fd.sip server_port=%fd.sport result=%evt.res)
priority: CRITICAL
tags: [container, mitre_execution, mitre_command_and_control]
36 changes: 36 additions & 0 deletions labs/lab9/policies/extra/hardening.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import rego.v1

deny contains msg if {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not input.spec.template.spec.securityContext.runAsNonRoot == true
not container.securityContext.runAsNonRoot == true
msg := sprintf("container %q must set runAsNonRoot: true at pod or container level", [container.name])
}

deny contains msg if {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not container.securityContext.allowPrivilegeEscalation == false
msg := sprintf("container %q must set allowPrivilegeEscalation: false", [container.name])
}

deny contains msg if {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
security_context := object.get(container, "securityContext", {})
capabilities := object.get(security_context, "capabilities", {})
dropped_capabilities := object.get(capabilities, "drop", [])
not "ALL" in dropped_capabilities
msg := sprintf("container %q must drop ALL Linux capabilities", [container.name])
}

deny contains msg if {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("container %q must set resources.limits.memory", [container.name])
}

100 changes: 100 additions & 0 deletions submissions/lab1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# 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: REMnux (Ubuntu 20.04-based)
- Docker version: `Docker version 26.1.3, build 26.1.3-0ubuntu1~20.04.1`

### 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: default `no` (no `--restart` flag used)

### Health Check
- HTTP code on `/`: `200`
- 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-12T10:31:40.266Z"
```
- Container uptime: 4bd57343c74b bkimminich/juice-shop:v20.0.0 "/nodejs/bin/node /j…" 14 minutes ago Up 14 minutes 127.0.0.1:3000->3000/tcp juice-shop

### Initial Surface Snapshot (from browser exploration)
- Login/Registration visible: [x] Yes [ ] No — notes: Login and Sign Up buttons present
- Product listing/search present: [x] Yes [ ] No — notes: Product cards displayed on homepage, search field available
- Admin or account area discoverable: [ ] Yes [x] No — notes: No direct admin link on landing page; authentication required
- Client-side errors in DevTools console: [ ] Yes [x] No — notes: Console clean, no errors detected
- Pre-populated local storage / cookies: language (set to 'en'), token (empty until login)


### 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 10:31:40 GMT
ETag: W/"26af-19ebb633283"
Content-Type: text/html; charset=UTF-8
Content-Length: 9903
Vary: Accept-Encoding
Date: Fri, 12 Jun 2026 10:34:55 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Which of these are MISSING? (cross-reference Lecture 1 OWASP Top 10:2025 — A06)
- [x] `Content-Security-Policy` - MISSING
- [x] `Strict-Transport-Security` - MISSING
- [ ] `X-Content-Type-Options: nosniff`
- [ ] `X-Frame-Options`

### Top 3 Risks Observed (2-3 sentences each, in your own words)
1. Broken Access Control (A01) — The API endpoint /api/Products/<id>/reviews returns data without authentication. This allows an unauthenticated attacker to read other users' reviews and potentially exfiltrate data, violating the principle of least privilege.
2. Cryptographic Failures (A02) — Absence of the HSTS header and operation over HTTP (in local environment) means that in production traffic could be intercepted. If the application transmits credentials or tokens without TLS, this leads to sensitive data exposure.
3. Security Misconfiguration (A05) — The complete absence of CSP and HSTS indicates a default 'open' configuration. Combined with intentionally vulnerable Juice Shop code, this creates a broad surface for XSS, clickjacking, and MIME-sniffing attacks.

## 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: [x] Yes — PR description showed my template (screenshot or link to draft PR)

## GitHub Community

### Actions Completed
- [x] Starred course repository
- [x] Starred [simple-container-com/api](https://github.com/simple-container-com/api)
- [x] Following Professor [@Cre-eD](https://github.com/Cre-eD)
- [x] Following TA [@Naghme98](https://github.com/Naghme98)
- [x] Following TA [@pierrepicaud](https://github.com/pierrepicaud)
- [x] Following 3+ classmates

### Why Stars Matter in Open Source
Stars are the currency of attention in the open-source ecosystem. A repository with 1000+ stars attracts more contributors and sponsors than an equivalent one with 10 stars.

## Bonus: CI Smoke Test

- Workflow file: `.github/workflows/lab1-smoke.yml`
- Trigger: `pull_request` on main
- Run URL (must be green): https://github.com/raaller/DevSecOps-Intro/actions/runs/27413678469
- Workflow run duration: 27s
- Curl response excerpt:
```
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Feature-Policy: payment 'self'
HTTP Status: 200
```
1 change: 1 addition & 0 deletions submissions/lab3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lab3 signing test
Loading
Loading