From 924a50cf70061b5aa688df961cd29defc8c8d53c Mon Sep 17 00:00:00 2001 From: Long1TaiL Date: Tue, 23 Jun 2026 21:41:35 +0300 Subject: [PATCH 1/3] lab 6: start submission --- submissions/lab6.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 submissions/lab6.md diff --git a/submissions/lab6.md b/submissions/lab6.md new file mode 100644 index 000000000..23aa36563 --- /dev/null +++ b/submissions/lab6.md @@ -0,0 +1 @@ +# Lab 6 submission \ No newline at end of file From 2a3b22aced8c5abf3c45c7e39f06bfb53ecd5542 Mon Sep 17 00:00:00 2001 From: Long1TaiL Date: Tue, 23 Jun 2026 22:37:25 +0300 Subject: [PATCH 2/3] lab 6: done --- app/Dockerfile | 24 ++++++ compose.yaml | 22 +++++ submissions/lab6.md | 200 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 app/Dockerfile create mode 100644 compose.yaml diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 000000000..592659d75 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.24.5-alpine AS builder + +WORKDIR /src + +COPY go.mod ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build \ + -trimpath \ + -ldflags="-s -w" \ + -o /quicknotes + +FROM gcr.io/distroless/static:nonroot + +COPY --from=builder /quicknotes /quicknotes +COPY --from=builder /src/seed.json /seed.json + +EXPOSE 8080 + +USER 65532:65532 + +ENTRYPOINT ["/quicknotes"] \ No newline at end of file diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 000000000..495cbf9ae --- /dev/null +++ b/compose.yaml @@ -0,0 +1,22 @@ +services: + quicknotes: + image: quicknotes:lab6 + build: + context: ./app + user: "0:0" + + ports: + - "8080:8080" + + environment: + ADDR: ":8080" + DATA_PATH: "/data/notes.json" + SEED_PATH: "/seed.json" + + volumes: + - quicknotes-data:/data + + restart: unless-stopped + +volumes: + quicknotes-data: \ No newline at end of file diff --git a/submissions/lab6.md b/submissions/lab6.md index 23aa36563..7c808b111 100644 --- a/submissions/lab6.md +++ b/submissions/lab6.md @@ -1 +1,199 @@ -# Lab 6 submission \ No newline at end of file +# Lab 6 submission + +## `dockerfile`: + +``` +FROM golang:1.24.5-alpine AS builder + +WORKDIR /src + +COPY go.mod ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build \ + -trimpath \ + -ldflags="-s -w" \ + -o /quicknotes + +FROM gcr.io/distroless/static:nonroot + +COPY --from=builder /quicknotes /quicknotes +COPY --from=builder /src/seed.json /seed.json + +EXPOSE 8080 + +USER 65532:65532 + +ENTRYPOINT ["/quicknotes"] +``` + +### docker images quicknotes:lab6 + +``` +docker images quicknotes:lab6 + i Info → U In Use +IMAGE ID DISK USAGE CONTENT SIZE EXTRA +quicknotes:lab6 + 89c2136f5efc 14.7MB 3.32MB +``` + +### docker inspect quicknotes:lab6 | jq '.[0].Config' + +``` +docker inspect quicknotes:lab6 | jq '.[0].Config' +{ + "Entrypoint": [ + "/quicknotes" + ], + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" + ], + "ExposedPorts": { + "8080/tcp": {} + }, + "User": "65532:65532", + "WorkingDir": "/home/nonroot" +} +``` + +``` +golang:1.24.5-alpine daae04ebad0c 394MB 83.3MB +``` + +## `compose.yalm`: + +``` +services: + quicknotes: + image: quicknotes:lab6 + build: + context: ./app + user: "0:0" + + ports: + - "8080:8080" + + environment: + ADDR: ":8080" + DATA_PATH: "/data/notes.json" + SEED_PATH: "/seed.json" + + volumes: + - quicknotes-data:/data + + restart: unless-stopped + +volumes: + quicknotes-data: + +``` + +``` +long1tail@Long1Tail:~/DevOps-Intro $ docker compose up --build -d +sleep 3 +curl -X POST -H 'Content-Type: application/json' \ + -d '{"title":"durable","body":"survive a restart"}' \ + http://localhost:8080/notes +curl -s http://localhost:8080/notes | grep durable +WARN[0000] Docker Compose requires buildx plugin to be installed +Sending build context to Docker daemon 5.188MB +Step 1/13 : FROM golang:1.24.5-alpine AS builder + ---> daae04ebad0c +Step 2/13 : WORKDIR /src + ---> Using cache + ---> 799bad952f0f +Step 3/13 : COPY go.mod ./ + ---> Using cache + ---> 7c1c40614b4e +Step 4/13 : RUN go mod download + ---> Using cache + ---> 822599abaeef +Step 5/13 : COPY . . + ---> Using cache + ---> 3540ad3ee96b +Step 6/13 : RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /quicknotes + ---> Using cache + ---> dff8776b7cc1 +Step 7/13 : FROM gcr.io/distroless/static:nonroot + ---> 963fa6c544fe +Step 8/13 : COPY --from=builder /quicknotes /quicknotes + ---> Using cache + ---> 1efb8b2954ad +Step 9/13 : COPY --from=builder /src/seed.json /seed.json + ---> Using cache + ---> 701937b2d2a6 +Step 10/13 : EXPOSE 8080 + ---> Using cache + ---> dfb1476938e2 +Step 11/13 : USER 65532:65532 + ---> Using cache + ---> 6715c8119c21 +Step 12/13 : ENTRYPOINT ["/quicknotes"] + ---> Using cache + ---> 89c2136f5efc +Step 13/13 : LABEL com.docker.compose.image.builder=classic + ---> Using cache + ---> 57ea3a70d968 +Successfully built 57ea3a70d968 +Successfully tagged quicknotes:lab6 +[+] up 2/2 + ✔ Image quicknotes:lab6 Built 0.4s + ✔ Container devops-intro-quicknotes-1 Running 0.0s +{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"} +[{"id":1,"title":"Welcome to QuickNotes","body":"This is the project you'll containerize, deploy, monitor, and harden across all 10 labs.","created_at":"2026-01-15T10:00:00Z"},{"id":2,"title":"Read app/main.go first","body":"Start by understanding the entry point — env vars, signal handling, graceful shutdown.","created_at":"2026-01-15T10:05:00Z"},{"id":3,"title":"DevOps mantra","body":"If it hurts, do it more often.","created_at":"2026-01-15T10:10:00Z"},{"id":4,"title":"Endpoint cheat-sheet","body":"GET /notes GET /notes/{id} POST /notes DELETE /notes/{id} GET /health GET /metrics","created_at":"2026-01-15T10:15:00Z"},{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"}] +long1tail@Long1Tail:~/DevOps-Intro $ docker compose down +[+] down 2/2 + ✔ Container devops-intro-quicknotes-1 Removed 0.3s + ✔ Network devops-intro_default Removed 0.3s +long1tail@Long1Tail:~/DevOps-Intro $ docker compose up -d +sleep 3 +curl -s http://localhost:8080/notes | grep durable +[+] up 2/2 + ✔ Network devops-intro_default Created 0.1s + ✔ Container devops-intro-quicknotes-1 Started 0.2s +[{"id":2,"title":"Read app/main.go first","body":"Start by understanding the entry point — env vars, signal handling, graceful shutdown.","created_at":"2026-01-15T10:05:00Z"},{"id":3,"title":"DevOps mantra","body":"If it hurts, do it more often.","created_at":"2026-01-15T10:10:00Z"},{"id":4,"title":"Endpoint cheat-sheet","body":"GET /notes GET /notes/{id} POST /notes DELETE /notes/{id} GET /health GET /metrics","created_at":"2026-01-15T10:15:00Z"},{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"},{"id":1,"title":"Welcome to QuickNotes","body":"This is the project you'll containerize, deploy, monitor, and harden across all 10 labs.","created_at":"2026-01-15T10:00:00Z"}] +long1tail@Long1Tail:~/DevOps-Intro $ docker compose down -v +[+] down 3/3 + ✔ Container devops-intro-quicknotes-1 Removed 0.3s + ✔ Volume devops-intro_quicknotes-data Removed 0.0s + ✔ Network devops-intro_default Removed 0.3s +long1tail@Long1Tail:~/DevOps-Intro $ docker compose up -d +sleep 3 +curl -s http://localhost:8080/notes | grep durable +[+] up 3/3 + ✔ Network devops-intro_default Created 0.0s + ✔ Volume devops-intro_quicknotes-data Created 0.0s + ✔ Container devops-intro-quicknotes-1 Started 0.1s + ``` + + ### a + + Docker caches layers. If you COPY . . before go mod download, any source code change invalidates the cache and forces dependencies to be downloaded again. Copying only go.mod and go.sum first lets Docker reuse the dependency layer, so rebuilding after a code change is much faster. + + ### b + + CGO_ENABLED=0 produces a fully static Go binary. Distroless static images do not include system libraries like glibc, so a CGO-enabled binary may fail to start because required shared libraries are missing. + + ### c + + It's a minimal runtime image containing only essentials like CA certificates and a non-root user. It does not include a shell, package manager, or common Linux utilities. Fewer installed packages mean a smaller attack surface and fewer CVEs. + + ### d + + -s -w removes symbol and debug information, reducing binary size at the cost of harder debugging. -trimpath removes local filesystem paths from the binary, improving reproducibility and avoiding leakage of build-machine details. + + ### e + + The best approach is to use functionality built into the application binary itself, for example a /healthz endpoint or a dedicated healthcheck command. This avoids adding extra tools and works naturally with distroless images. + + + ### f + + Because named volumes are managed separately from containers. docker compose down removes containers and networks, but keeps volumes. To delete the data, run docker compose down -v or remove the volume explicitly. + + ### g + + It only waits for the dependency container to start, not for the service inside it to become ready. This can cause race conditions where your app starts before the database is accepting connections and crashes on startup. \ No newline at end of file From ce4906df8e39d68b1f07b51d548396b2ad3993b6 Mon Sep 17 00:00:00 2001 From: long1tail Date: Tue, 7 Jul 2026 18:48:30 +0300 Subject: [PATCH 3/3] lab9: Done Signed-off-by: long1tail --- app/handlers.go | 17 +- app/handlers_test.go | 9 + sbom.json | 481 ++++++++++++ .../artifacts lab 9/zap-baseline-after.html | 618 +++++++++++++++ .../artifacts lab 9/zap-baseline-after.json | 103 +++ .../artifacts lab 9/zap-baseline-before.html | 598 ++++++++++++++ .../artifacts lab 9/zap-baseline-before.json | 99 +++ submissions/lab6.md | 199 ----- submissions/lab9.md | 727 ++++++++++++++++++ 9 files changed, 2650 insertions(+), 201 deletions(-) create mode 100644 sbom.json create mode 100644 submissions/artifacts lab 9/zap-baseline-after.html create mode 100644 submissions/artifacts lab 9/zap-baseline-after.json create mode 100644 submissions/artifacts lab 9/zap-baseline-before.html create mode 100644 submissions/artifacts lab 9/zap-baseline-before.json delete mode 100644 submissions/lab6.md create mode 100644 submissions/lab9.md diff --git a/app/handlers.go b/app/handlers.go index c534979c5..e2efbef72 100644 --- a/app/handlers.go +++ b/app/handlers.go @@ -26,7 +26,20 @@ func NewServer(store *Store) *Server { return &Server{store: store, requestsByCode: by} } -func (s *Server) Routes() *http.ServeMux { +func SecurityHeaders(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("Cross-Origin-Resource-Policy", "same-origin") + w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("X-Frame-Options", "DENY") + w.Header().Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'") + + next.ServeHTTP(w, r) + }) +} + +func (s *Server) Routes() http.Handler { mux := http.NewServeMux() mux.HandleFunc("GET /health", s.wrap(s.handleHealth)) mux.HandleFunc("GET /metrics", s.wrap(s.handleMetrics)) @@ -34,7 +47,7 @@ func (s *Server) Routes() *http.ServeMux { mux.HandleFunc("POST /notes", s.wrap(s.handleCreateNote)) mux.HandleFunc("GET /notes/{id}", s.wrap(s.handleGetNote)) mux.HandleFunc("DELETE /notes/{id}", s.wrap(s.handleDeleteNote)) - return mux + return SecurityHeaders(mux) } type statusWriter struct { diff --git a/app/handlers_test.go b/app/handlers_test.go index 9dff2e3e5..82b4faafb 100644 --- a/app/handlers_test.go +++ b/app/handlers_test.go @@ -131,3 +131,12 @@ func TestMetrics_ExposesPrometheusFormat(t *testing.T) { } } +func TestSecurityHeaders(t *testing.T) { + srv := newTestServer(t) + + rec := do(t, srv, http.MethodGet, "/health", nil) + + if rec.Header().Get("X-Content-Type-Options") != "nosniff" { + t.Fatal("missing X-Content-Type-Options header") + } +} diff --git a/sbom.json b/sbom.json new file mode 100644 index 000000000..91b5be6fa --- /dev/null +++ b/sbom.json @@ -0,0 +1,481 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7", + "serialNumber": "urn:uuid:9e850e41-d9e8-46dd-89b0-a07d2c22eebb", + "version": 1, + "metadata": { + "timestamp": "2026-07-03T20:46:51+00:00", + "tools": { + "components": [ + { + "type": "application", + "manufacturer": { + "name": "Aqua Security Software Ltd." + }, + "group": "aquasecurity", + "name": "trivy", + "version": "0.72.0" + } + ] + }, + "component": { + "bom-ref": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "type": "container", + "name": "quicknotes:lab6", + "purl": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:187cfc6d1e3e8a40a5e64653bcd3239c140807dcf1c09e48021178705a5a6139" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:275a30dd8ce958b21daa9ad962c6fbc09f98306ee2f486b65c9075dc257b1412" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:4cde6b0bb6f50a5f255eef7b2a42162c661cf776b803225dcac9a659e396bb6b" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:4d049f83d9cf21d1f5cc0e11deaf36df02790d0e60c1a3829538fb4b61685368" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:5892e2ebce362e40d2093eb8a7e460aa390423bf3a948d509edad0a1d413e508" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:5fd2536c39c0700be8b7b4344e375196da2f126842fd8ede66996a18860a3890" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:621c35e751a51a9a9dc3e80aa0b7fe8be2a93402ea6ccd307d30852cd7776cda" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:6f1cdceb6a3146f0ccb986521156bef8a422cdbb0863396f7f751f575ba308f4" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:92cb9c37b7d3957ac56645a979418f65e6c5bdba00eb99622affae5fc124ac07" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:ad51d0769d16ba578106a177987dfe3d2e02c1668c852b795b2f6b024068242a" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:af5aa97ebe6ce1604747ec1e21af7136ded391bcabe4acef882e718a87c86bcc" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:bd3cdfae1d3fdd83a2231d608969b38b82349777c2fff9a7c12d54f8ac5c9b38" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:bec7e6bb35e05d1284f28b10d2150c259717d91c658c4c10c08424bb9466caba" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:c8b007d0206e4b10ed4d3b3d99dfeab47c2648e82011989fd78a5731baf33fc3" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:ImageID", + "value": "sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3" + }, + { + "name": "aquasecurity:trivy:Reference", + "value": "quicknotes:lab6" + }, + { + "name": "aquasecurity:trivy:RepoDigest", + "value": "quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3" + }, + { + "name": "aquasecurity:trivy:RepoTag", + "value": "quicknotes:lab6" + }, + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + }, + { + "name": "aquasecurity:trivy:Size", + "value": "9106944" + } + ] + } + }, + "components": [ + { + "bom-ref": "54cc6d80-592b-414e-b3de-cbfad43ed8e4", + "type": "operating-system", + "name": "debian", + "version": "13.5", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "debian" + } + ] + }, + { + "bom-ref": "615ad830-9d25-4bec-a0e1-56eecf392d13", + "type": "application", + "name": "quicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Santiago Vila " + }, + "name": "base-files", + "version": "13.8+deb13u5", + "licenses": [ + { + "license": { + "id": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "verbatim" + } + } + ], + "purl": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:92cb9c37b7d3957ac56645a979418f65e6c5bdba00eb99622affae5fc124ac07" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:47de5dd0b812c573630914955e26abda537e09b5286a824c96e22e3854d4dd53" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "base-files@13.8+deb13u5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "base-files" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "13.8+deb13u5" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Mime-Support Packagers " + }, + "name": "media-types", + "version": "13.0.0", + "licenses": [ + { + "license": { + "name": "ad-hoc" + } + } + ], + "purl": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:275a30dd8ce958b21daa9ad962c6fbc09f98306ee2f486b65c9075dc257b1412" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:d6b1b89eccacc15c2420b2776d72c1dae334a00805ed9af54bf2f71e4d536f28" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "media-types@13.0.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "media-types" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "13.0.0" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Marco d'Itri " + }, + "name": "netbase", + "version": "6.5", + "licenses": [ + { + "license": { + "id": "GPL-2.0-only" + } + } + ], + "purl": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:621c35e751a51a9a9dc3e80aa0b7fe8be2a93402ea6ccd307d30852cd7776cda" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:c172f21841dff4c8cf45cde46589c1c2616cefe7e819965e92e6d3475c428aa0" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "netbase@6.5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "netbase" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "6.5" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "GNU Libc Maintainers " + }, + "name": "tzdata-legacy", + "version": "2026b-0+deb13u1", + "licenses": [ + { + "license": { + "name": "public-domain" + } + } + ], + "purl": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:bec7e6bb35e05d1284f28b10d2150c259717d91c658c4c10c08424bb9466caba" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:99ba982a9142213c751a1709dcf088e63d8601f03b3f211bae037be698fef270" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "tzdata-legacy@2026b-0+deb13u1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "tzdata" + }, + { + "name": "aquasecurity:trivy:SrcRelease", + "value": "0+deb13u1" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2026b" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "GNU Libc Maintainers " + }, + "name": "tzdata", + "version": "2026b-0+deb13u1", + "licenses": [ + { + "license": { + "name": "public-domain" + } + } + ], + "purl": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:c8b007d0206e4b10ed4d3b3d99dfeab47c2648e82011989fd78a5731baf33fc3" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:99515e7b4d35e0652d3b0fde571b6ec269222ecacc506f026e1758d6261e9109" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "tzdata@2026b-0+deb13u1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "tzdata" + }, + { + "name": "aquasecurity:trivy:SrcRelease", + "value": "0+deb13u1" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2026b" + } + ] + }, + { + "bom-ref": "pkg:golang/quicknotes", + "type": "library", + "name": "quicknotes", + "purl": "pkg:golang/quicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:aa0574b2f7185ab28e65d536c216699d8eeb45d74924214e26efae7f53e01e4f" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "quicknotes" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/stdlib@v1.24.5", + "type": "library", + "name": "stdlib", + "version": "v1.24.5", + "purl": "pkg:golang/stdlib@v1.24.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:aa0574b2f7185ab28e65d536c216699d8eeb45d74924214e26efae7f53e01e4f" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "stdlib@v1.24.5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + } + ], + "dependencies": [ + { + "ref": "54cc6d80-592b-414e-b3de-cbfad43ed8e4", + "dependsOn": [ + "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5" + ] + }, + { + "ref": "615ad830-9d25-4bec-a0e1-56eecf392d13", + "dependsOn": [ + "pkg:golang/quicknotes" + ] + }, + { + "ref": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:golang/quicknotes", + "dependsOn": [ + "pkg:golang/stdlib@v1.24.5" + ] + }, + { + "ref": "pkg:golang/stdlib@v1.24.5", + "dependsOn": [] + }, + { + "ref": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "dependsOn": [ + "54cc6d80-592b-414e-b3de-cbfad43ed8e4", + "615ad830-9d25-4bec-a0e1-56eecf392d13" + ] + } + ], + "vulnerabilities": [] +} diff --git a/submissions/artifacts lab 9/zap-baseline-after.html b/submissions/artifacts lab 9/zap-baseline-after.html new file mode 100644 index 000000000..ad21ca4db --- /dev/null +++ b/submissions/artifacts lab 9/zap-baseline-after.html @@ -0,0 +1,618 @@ + + + + +ZAP Scanning Report + + + +

+ + + ZAP Scanning Report +

+

+ + +

+ + Site: http://localhost:8080 + +

+ +

+ Generated on Tue, 7 Jul 2026 15:24:25 +

+ +

+ ZAP Version: 2.17.0 +

+ +

+ ZAP by Checkmarx +

+ + +

Summary of Alerts

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Risk LevelNumber of Alerts
+
High
+
+
0
+
+
Medium
+
+
0
+
+
Low
+
+
0
+
+
Informational
+
+
1
+
+
False Positives:
+
+
0
+
+
+ + + +

Insights

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LevelReasonSiteDescriptionStatistic
+
Info
+
+
Informational
+
+
http://localhost:8080
+
+
Percentage of responses with status code 4xx
+
+
100 %
+
+
Info
+
+
Informational
+
+
http://localhost:8080
+
+
Percentage of endpoints with content type text/plain
+
+
100 %
+
+
Info
+
+
Informational
+
+
http://localhost:8080
+
+
Percentage of endpoints with method GET
+
+
100 %
+
+
Info
+
+
Informational
+
+
http://localhost:8080
+
+
Count of total endpoints
+
+
2
+
+
+ + + + + + +

Summary of Sequences

+

For each step: result (Pass/Fail) - risk (of highest alert(s) for the step, if any).

+ + + + + + + + +

Alerts

+ + + + + + + + + + + + + + +
NameRisk LevelNumber of Instances
Storable and Cacheable ContentInformational3
+
+ + + +

Alert Detail

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Informational
Storable and Cacheable Content
Description +
The response contents are storable by caching components such as proxy servers, and may be retrieved directly from the cache, rather than from the origin server by the caching servers, in response to similar requests from other users. If the response data is sensitive, personal or user-specific, this may result in sensitive information being leaked. In some cases, this may even result in a user gaining complete control of the session of another user, depending on the configuration of the caching components in use in their environment. This is primarily an issue where "shared" caching servers such as "proxy" caches are configured on the local network. This configuration is typically found in corporate or educational environments, for instance.
+ +
URLhttp://localhost:8080
Node Namehttp://localhost:8080
MethodGET
Parameter
Attack
Evidence
Other Info +
In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
+ +
URLhttp://localhost:8080/robots.txt
Node Namehttp://localhost:8080/robots.txt
MethodGET
Parameter
Attack
Evidence
Other Info +
In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
+ +
URLhttp://localhost:8080/sitemap.xml
Node Namehttp://localhost:8080/sitemap.xml
MethodGET
Parameter
Attack
Evidence
Other Info +
In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
+ +
Instances3
Solution +
Validate that the response does not contain sensitive, personal or user-specific information. If it does, consider the use of the following HTTP response headers, to limit, or prevent the content being stored and retrieved from the cache by another user:
+
+ +
Cache-Control: no-cache, no-store, must-revalidate, private
+
+ +
Pragma: no-cache
+
+ +
Expires: 0
+
+ +
This configuration directs both HTTP 1.0 and HTTP 1.1 compliant caching servers to not store the response, and to not retrieve the response (without validation) from the cache, in response to a similar request.
+ +
Reference + https://datatracker.ietf.org/doc/html/rfc7234 +
+ + https://datatracker.ietf.org/doc/html/rfc7231 +
+ + https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + +
CWE Id524
WASC Id13
Plugin Id10049
+
+ + + + + +

Sequence Details

+ With the associated active scan results. + + + +
+ + + + + + + diff --git a/submissions/artifacts lab 9/zap-baseline-after.json b/submissions/artifacts lab 9/zap-baseline-after.json new file mode 100644 index 000000000..1326e9479 --- /dev/null +++ b/submissions/artifacts lab 9/zap-baseline-after.json @@ -0,0 +1,103 @@ +{ + "@programName": "ZAP", + "@version": "2.17.0", + "@generated": "Tue, 7 Jul 2026 15:24:25", + "created": "2026-07-07T15:24:25.946051577Z", + "insights":[ + { + "level": "Info", + "reason": "Informational", + "site": "http://localhost:8080", + "key": "insight.code.4xx", + "description": "Percentage of responses with status code 4xx", + "statistic": "100" + }, + { + "level": "Info", + "reason": "Informational", + "site": "http://localhost:8080", + "key": "insight.endpoint.ctype.text/plain", + "description": "Percentage of endpoints with content type text/plain", + "statistic": "100" + }, + { + "level": "Info", + "reason": "Informational", + "site": "http://localhost:8080", + "key": "insight.endpoint.method.GET", + "description": "Percentage of endpoints with method GET", + "statistic": "100" + }, + { + "level": "Info", + "reason": "Informational", + "site": "http://localhost:8080", + "key": "insight.endpoint.total", + "description": "Count of total endpoints", + "statistic": "2" + } + ], + "site":[ + { + "@name": "http://localhost:8080", + "@host": "localhost", + "@port": "8080", + "@ssl": "false", + "alerts": [ + { + "pluginid": "10049", + "alertRef": "10049-3", + "alert": "Storable and Cacheable Content", + "name": "Storable and Cacheable Content", + "riskcode": "0", + "confidence": "2", + "riskdesc": "Informational (Medium)", + "desc": "

The response contents are storable by caching components such as proxy servers, and may be retrieved directly from the cache, rather than from the origin server by the caching servers, in response to similar requests from other users. If the response data is sensitive, personal or user-specific, this may result in sensitive information being leaked. In some cases, this may even result in a user gaining complete control of the session of another user, depending on the configuration of the caching components in use in their environment. This is primarily an issue where \"shared\" caching servers such as \"proxy\" caches are configured on the local network. This configuration is typically found in corporate or educational environments, for instance.

", + "instances":[ + { + "id": "0", + "uri": "http://localhost:8080", + "nodeName": "http:\/\/localhost:8080", + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + }, + { + "id": "3", + "uri": "http://localhost:8080/robots.txt", + "nodeName": "http:\/\/localhost:8080\/robots.txt", + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + }, + { + "id": "1", + "uri": "http://localhost:8080/sitemap.xml", + "nodeName": "http:\/\/localhost:8080\/sitemap.xml", + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + } + ], + "count": "3", + "systemic": false, + "solution": "

Validate that the response does not contain sensitive, personal or user-specific information. If it does, consider the use of the following HTTP response headers, to limit, or prevent the content being stored and retrieved from the cache by another user:

Cache-Control: no-cache, no-store, must-revalidate, private

Pragma: no-cache

Expires: 0

This configuration directs both HTTP 1.0 and HTTP 1.1 compliant caching servers to not store the response, and to not retrieve the response (without validation) from the cache, in response to a similar request.

", + "otherinfo": "

In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.

", + "reference": "

https://datatracker.ietf.org/doc/html/rfc7234

https://datatracker.ietf.org/doc/html/rfc7231

https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html

", + "cweid": "524", + "wascid": "13", + "sourceid": "7" + } + ] + } + ], + "sequences":[ + ] + +} diff --git a/submissions/artifacts lab 9/zap-baseline-before.html b/submissions/artifacts lab 9/zap-baseline-before.html new file mode 100644 index 000000000..1ef3f9dc0 --- /dev/null +++ b/submissions/artifacts lab 9/zap-baseline-before.html @@ -0,0 +1,598 @@ + + + + +ZAP Scanning Report + + + +

+ + + ZAP Scanning Report +

+

+ + +

+ + Site: http://localhost:8080 + +

+ +

+ Generated on Tue, 7 Jul 2026 11:25:20 +

+ +

+ ZAP Version: 2.16.1 +

+ +

+ ZAP by Checkmarx +

+ + +

Summary of Alerts

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Risk LevelNumber of Alerts
+
High
+
+
0
+
+
Medium
+
+
0
+
+
Low
+
+
1
+
+
Informational
+
+
1
+
+
False Positives:
+
+
0
+
+
+ + + + +

Summary of Sequences

+

For each step: result (Pass/Fail) - risk (of highest alert(s) for the step, if any).

+ + + + + + +

Alerts

+ + + + + + + + + + + + + + + + + + + + + + +
NameRisk LevelNumber of Instances
ZAP is Out of DateLow1
Storable and Cacheable ContentInformational3
+
+ + + +

Alert Detail

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Low
ZAP is Out of Date
Description +
The version of ZAP you are using to test your app is out of date and is no longer being updated.
+
+ +
The risk level is set based on how out of date your ZAP version is.
+ +
URLhttp://localhost:8080
MethodGET
Parameter
Attack
Evidence
Other InfoThe latest version of ZAP is 2.17.0
Instances1
Solution +
Download the latest version of ZAP from https://www.zaproxy.org/download/ and install it.
+ +
Reference + https://www.zaproxy.org/download/ + +
CWE Id1104
WASC Id45
Plugin Id10116
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Informational
Storable and Cacheable Content
Description +
The response contents are storable by caching components such as proxy servers, and may be retrieved directly from the cache, rather than from the origin server by the caching servers, in response to similar requests from other users. If the response data is sensitive, personal or user-specific, this may result in sensitive information being leaked. In some cases, this may even result in a user gaining complete control of the session of another user, depending on the configuration of the caching components in use in their environment. This is primarily an issue where "shared" caching servers such as "proxy" caches are configured on the local network. This configuration is typically found in corporate or educational environments, for instance.
+ +
URLhttp://localhost:8080
MethodGET
Parameter
Attack
Evidence
Other InfoIn the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
URLhttp://localhost:8080/robots.txt
MethodGET
Parameter
Attack
Evidence
Other InfoIn the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
URLhttp://localhost:8080/sitemap.xml
MethodGET
Parameter
Attack
Evidence
Other InfoIn the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.
Instances3
Solution +
Validate that the response does not contain sensitive, personal or user-specific information. If it does, consider the use of the following HTTP response headers, to limit, or prevent the content being stored and retrieved from the cache by another user:
+
+ +
Cache-Control: no-cache, no-store, must-revalidate, private
+
+ +
Pragma: no-cache
+
+ +
Expires: 0
+
+ +
This configuration directs both HTTP 1.0 and HTTP 1.1 compliant caching servers to not store the response, and to not retrieve the response (without validation) from the cache, in response to a similar request.
+ +
Reference + https://datatracker.ietf.org/doc/html/rfc7234 +
+ + https://datatracker.ietf.org/doc/html/rfc7231 +
+ + https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + +
CWE Id524
WASC Id13
Plugin Id10049
+
+ + + + + +

Sequence Details

+ With the associated active scan results. + + + +
+ + + + + + + diff --git a/submissions/artifacts lab 9/zap-baseline-before.json b/submissions/artifacts lab 9/zap-baseline-before.json new file mode 100644 index 000000000..ab2cb5c9a --- /dev/null +++ b/submissions/artifacts lab 9/zap-baseline-before.json @@ -0,0 +1,99 @@ +{ + "@programName": "ZAP", + "@version": "2.16.1", + "@generated": "Tue, 7 Jul 2026 11:25:20", + "created": "2026-07-07T11:25:20.305323059Z", + "site":[ + { + "@name": "http://localhost:8080", + "@host": "localhost", + "@port": "8080", + "@ssl": "false", + "alerts": [ + { + "pluginid": "10116", + "alertRef": "10116", + "alert": "ZAP is Out of Date", + "name": "ZAP is Out of Date", + "riskcode": "1", + "confidence": "3", + "riskdesc": "Low (High)", + "desc": "

The version of ZAP you are using to test your app is out of date and is no longer being updated.

The risk level is set based on how out of date your ZAP version is.

", + "instances":[ + { + "id": "0", + "uri": "http://localhost:8080", + "nodeName": null, + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "The latest version of ZAP is 2.17.0" + } + ], + "count": "1", + "systemic": false, + "solution": "

Download the latest version of ZAP from https://www.zaproxy.org/download/ and install it.

", + "otherinfo": "

The latest version of ZAP is 2.17.0

", + "reference": "

https://www.zaproxy.org/download/

", + "cweid": "1104", + "wascid": "45", + "sourceid": "7" + }, + { + "pluginid": "10049", + "alertRef": "10049-3", + "alert": "Storable and Cacheable Content", + "name": "Storable and Cacheable Content", + "riskcode": "0", + "confidence": "2", + "riskdesc": "Informational (Medium)", + "desc": "

The response contents are storable by caching components such as proxy servers, and may be retrieved directly from the cache, rather than from the origin server by the caching servers, in response to similar requests from other users. If the response data is sensitive, personal or user-specific, this may result in sensitive information being leaked. In some cases, this may even result in a user gaining complete control of the session of another user, depending on the configuration of the caching components in use in their environment. This is primarily an issue where \"shared\" caching servers such as \"proxy\" caches are configured on the local network. This configuration is typically found in corporate or educational environments, for instance.

", + "instances":[ + { + "id": "1", + "uri": "http://localhost:8080", + "nodeName": null, + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + }, + { + "id": "4", + "uri": "http://localhost:8080/robots.txt", + "nodeName": null, + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + }, + { + "id": "3", + "uri": "http://localhost:8080/sitemap.xml", + "nodeName": null, + "method": "GET", + "param": "", + "attack": "", + "evidence": "", + "otherinfo": "In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234." + } + ], + "count": "3", + "systemic": false, + "solution": "

Validate that the response does not contain sensitive, personal or user-specific information. If it does, consider the use of the following HTTP response headers, to limit, or prevent the content being stored and retrieved from the cache by another user:

Cache-Control: no-cache, no-store, must-revalidate, private

Pragma: no-cache

Expires: 0

This configuration directs both HTTP 1.0 and HTTP 1.1 compliant caching servers to not store the response, and to not retrieve the response (without validation) from the cache, in response to a similar request.

", + "otherinfo": "

In the absence of an explicitly specified caching lifetime directive in the response, a liberal lifetime heuristic of 1 year was assumed. This is permitted by rfc7234.

", + "reference": "

https://datatracker.ietf.org/doc/html/rfc7234

https://datatracker.ietf.org/doc/html/rfc7231

https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html

", + "cweid": "524", + "wascid": "13", + "sourceid": "7" + } + ] + } + ], + "sequences":[ + ] + +} diff --git a/submissions/lab6.md b/submissions/lab6.md deleted file mode 100644 index 7c808b111..000000000 --- a/submissions/lab6.md +++ /dev/null @@ -1,199 +0,0 @@ -# Lab 6 submission - -## `dockerfile`: - -``` -FROM golang:1.24.5-alpine AS builder - -WORKDIR /src - -COPY go.mod ./ -RUN go mod download - -COPY . . - -RUN CGO_ENABLED=0 go build \ - -trimpath \ - -ldflags="-s -w" \ - -o /quicknotes - -FROM gcr.io/distroless/static:nonroot - -COPY --from=builder /quicknotes /quicknotes -COPY --from=builder /src/seed.json /seed.json - -EXPOSE 8080 - -USER 65532:65532 - -ENTRYPOINT ["/quicknotes"] -``` - -### docker images quicknotes:lab6 - -``` -docker images quicknotes:lab6 - i Info → U In Use -IMAGE ID DISK USAGE CONTENT SIZE EXTRA -quicknotes:lab6 - 89c2136f5efc 14.7MB 3.32MB -``` - -### docker inspect quicknotes:lab6 | jq '.[0].Config' - -``` -docker inspect quicknotes:lab6 | jq '.[0].Config' -{ - "Entrypoint": [ - "/quicknotes" - ], - "Env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" - ], - "ExposedPorts": { - "8080/tcp": {} - }, - "User": "65532:65532", - "WorkingDir": "/home/nonroot" -} -``` - -``` -golang:1.24.5-alpine daae04ebad0c 394MB 83.3MB -``` - -## `compose.yalm`: - -``` -services: - quicknotes: - image: quicknotes:lab6 - build: - context: ./app - user: "0:0" - - ports: - - "8080:8080" - - environment: - ADDR: ":8080" - DATA_PATH: "/data/notes.json" - SEED_PATH: "/seed.json" - - volumes: - - quicknotes-data:/data - - restart: unless-stopped - -volumes: - quicknotes-data: - -``` - -``` -long1tail@Long1Tail:~/DevOps-Intro $ docker compose up --build -d -sleep 3 -curl -X POST -H 'Content-Type: application/json' \ - -d '{"title":"durable","body":"survive a restart"}' \ - http://localhost:8080/notes -curl -s http://localhost:8080/notes | grep durable -WARN[0000] Docker Compose requires buildx plugin to be installed -Sending build context to Docker daemon 5.188MB -Step 1/13 : FROM golang:1.24.5-alpine AS builder - ---> daae04ebad0c -Step 2/13 : WORKDIR /src - ---> Using cache - ---> 799bad952f0f -Step 3/13 : COPY go.mod ./ - ---> Using cache - ---> 7c1c40614b4e -Step 4/13 : RUN go mod download - ---> Using cache - ---> 822599abaeef -Step 5/13 : COPY . . - ---> Using cache - ---> 3540ad3ee96b -Step 6/13 : RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /quicknotes - ---> Using cache - ---> dff8776b7cc1 -Step 7/13 : FROM gcr.io/distroless/static:nonroot - ---> 963fa6c544fe -Step 8/13 : COPY --from=builder /quicknotes /quicknotes - ---> Using cache - ---> 1efb8b2954ad -Step 9/13 : COPY --from=builder /src/seed.json /seed.json - ---> Using cache - ---> 701937b2d2a6 -Step 10/13 : EXPOSE 8080 - ---> Using cache - ---> dfb1476938e2 -Step 11/13 : USER 65532:65532 - ---> Using cache - ---> 6715c8119c21 -Step 12/13 : ENTRYPOINT ["/quicknotes"] - ---> Using cache - ---> 89c2136f5efc -Step 13/13 : LABEL com.docker.compose.image.builder=classic - ---> Using cache - ---> 57ea3a70d968 -Successfully built 57ea3a70d968 -Successfully tagged quicknotes:lab6 -[+] up 2/2 - ✔ Image quicknotes:lab6 Built 0.4s - ✔ Container devops-intro-quicknotes-1 Running 0.0s -{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"} -[{"id":1,"title":"Welcome to QuickNotes","body":"This is the project you'll containerize, deploy, monitor, and harden across all 10 labs.","created_at":"2026-01-15T10:00:00Z"},{"id":2,"title":"Read app/main.go first","body":"Start by understanding the entry point — env vars, signal handling, graceful shutdown.","created_at":"2026-01-15T10:05:00Z"},{"id":3,"title":"DevOps mantra","body":"If it hurts, do it more often.","created_at":"2026-01-15T10:10:00Z"},{"id":4,"title":"Endpoint cheat-sheet","body":"GET /notes GET /notes/{id} POST /notes DELETE /notes/{id} GET /health GET /metrics","created_at":"2026-01-15T10:15:00Z"},{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"}] -long1tail@Long1Tail:~/DevOps-Intro $ docker compose down -[+] down 2/2 - ✔ Container devops-intro-quicknotes-1 Removed 0.3s - ✔ Network devops-intro_default Removed 0.3s -long1tail@Long1Tail:~/DevOps-Intro $ docker compose up -d -sleep 3 -curl -s http://localhost:8080/notes | grep durable -[+] up 2/2 - ✔ Network devops-intro_default Created 0.1s - ✔ Container devops-intro-quicknotes-1 Started 0.2s -[{"id":2,"title":"Read app/main.go first","body":"Start by understanding the entry point — env vars, signal handling, graceful shutdown.","created_at":"2026-01-15T10:05:00Z"},{"id":3,"title":"DevOps mantra","body":"If it hurts, do it more often.","created_at":"2026-01-15T10:10:00Z"},{"id":4,"title":"Endpoint cheat-sheet","body":"GET /notes GET /notes/{id} POST /notes DELETE /notes/{id} GET /health GET /metrics","created_at":"2026-01-15T10:15:00Z"},{"id":5,"title":"durable","body":"survive a restart","created_at":"2026-06-23T19:29:07.590969929Z"},{"id":1,"title":"Welcome to QuickNotes","body":"This is the project you'll containerize, deploy, monitor, and harden across all 10 labs.","created_at":"2026-01-15T10:00:00Z"}] -long1tail@Long1Tail:~/DevOps-Intro $ docker compose down -v -[+] down 3/3 - ✔ Container devops-intro-quicknotes-1 Removed 0.3s - ✔ Volume devops-intro_quicknotes-data Removed 0.0s - ✔ Network devops-intro_default Removed 0.3s -long1tail@Long1Tail:~/DevOps-Intro $ docker compose up -d -sleep 3 -curl -s http://localhost:8080/notes | grep durable -[+] up 3/3 - ✔ Network devops-intro_default Created 0.0s - ✔ Volume devops-intro_quicknotes-data Created 0.0s - ✔ Container devops-intro-quicknotes-1 Started 0.1s - ``` - - ### a - - Docker caches layers. If you COPY . . before go mod download, any source code change invalidates the cache and forces dependencies to be downloaded again. Copying only go.mod and go.sum first lets Docker reuse the dependency layer, so rebuilding after a code change is much faster. - - ### b - - CGO_ENABLED=0 produces a fully static Go binary. Distroless static images do not include system libraries like glibc, so a CGO-enabled binary may fail to start because required shared libraries are missing. - - ### c - - It's a minimal runtime image containing only essentials like CA certificates and a non-root user. It does not include a shell, package manager, or common Linux utilities. Fewer installed packages mean a smaller attack surface and fewer CVEs. - - ### d - - -s -w removes symbol and debug information, reducing binary size at the cost of harder debugging. -trimpath removes local filesystem paths from the binary, improving reproducibility and avoiding leakage of build-machine details. - - ### e - - The best approach is to use functionality built into the application binary itself, for example a /healthz endpoint or a dedicated healthcheck command. This avoids adding extra tools and works naturally with distroless images. - - - ### f - - Because named volumes are managed separately from containers. docker compose down removes containers and networks, but keeps volumes. To delete the data, run docker compose down -v or remove the volume explicitly. - - ### g - - It only waits for the dependency container to start, not for the service inside it to become ready. This can cause race conditions where your app starts before the database is accepting connections and crashes on startup. \ No newline at end of file diff --git a/submissions/lab9.md b/submissions/lab9.md new file mode 100644 index 000000000..d410832d9 --- /dev/null +++ b/submissions/lab9.md @@ -0,0 +1,727 @@ +# Lab 9 submission + +### trivy image quicknotes:lab6 --severity HIGH,CRITICAL +``` +2026-07-03T23:33:55+03:00 INFO [vulndb] Need to update DB +2026-07-03T23:33:55+03:00 INFO [vulndb] Downloading vulnerability DB... +2026-07-03T23:33:55+03:00 INFO [vulndb] Downloading artifact... repo="mirror.gcr.io/aquasec/trivy-db:2" +98.92 MiB / 98.92 MiB [--------------------------------------------------------------------------------------------------------------------------------------] 100.00% 12.75 MiB p/s 8.0s +2026-07-03T23:34:05+03:00 INFO [vulndb] Artifact successfully downloaded repo="mirror.gcr.io/aquasec/trivy-db:2" +2026-07-03T23:34:05+03:00 INFO [vuln] Vulnerability scanning is enabled +2026-07-03T23:34:05+03:00 INFO [secret] Secret scanning is enabled +2026-07-03T23:34:05+03:00 INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning +2026-07-03T23:34:05+03:00 INFO [secret] Please see https://trivy.dev/docs/v0.72/guide/scanner/secret#recommendation for faster secret detection +2026-07-03T23:34:05+03:00 INFO Detected OS family="debian" version="13.5" +2026-07-03T23:34:05+03:00 INFO [debian] Detecting vulnerabilities... os_version="13" pkg_num=5 +2026-07-03T23:34:05+03:00 INFO Number of language-specific files num=1 +2026-07-03T23:34:05+03:00 INFO [gobinary] Detecting vulnerabilities... +2026-07-03T23:34:05+03:00 WARN Using severities from other vendors for some vulnerabilities. Read https://trivy.dev/docs/v0.72/guide/scanner/vulnerability#severity-selection for details. + +Report Summary + +┌───────────────────────────────┬──────────┬─────────────────┬─────────┐ +│ Target │ Type │ Vulnerabilities │ Secrets │ +├───────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ quicknotes:lab6 (debian 13.5) │ debian │ 0 │ - │ +├───────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ quicknotes │ gobinary │ 13 │ - │ +└───────────────────────────────┴──────────┴─────────────────┴─────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + + +quicknotes (gobinary) + +Total: 13 (HIGH: 12, CRITICAL: 1) + +┌─────────┬────────────────┬──────────┬────────┬───────────────────┬──────────────────────────────┬──────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────┼────────────────┼──────────┼────────┼───────────────────┼──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ stdlib │ CVE-2025-68121 │ CRITICAL │ fixed │ v1.24.5 │ 1.24.13, 1.25.7, 1.26.0-rc.3 │ crypto/tls: crypto/tls: Incorrect certificate validation │ +│ │ │ │ │ │ │ during TLS session resumption │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2025-68121 │ +│ ├────────────────┼──────────┤ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2025-61726 │ HIGH │ │ │ 1.24.12, 1.25.6 │ golang: net/url: Memory exhaustion in query parameter │ +│ │ │ │ │ │ │ parsing in net/url │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2025-61726 │ +│ ├────────────────┤ │ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2025-61729 │ │ │ │ 1.24.11, 1.25.5 │ crypto/x509: golang: Denial of Service due to excessive │ +│ │ │ │ │ │ │ resource consumption via crafted... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2025-61729 │ +│ ├────────────────┤ │ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-25679 │ │ │ │ 1.25.8, 1.26.1 │ net/url: Incorrect parsing of IPv6 host literals in net/url │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-25679 │ +│ ├────────────────┤ │ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-27145 │ │ │ │ 1.25.11, 1.26.4 │ crypto/x509: golang: golang crypto/x509: Denial of Service │ +│ │ │ │ │ │ │ via excessive processing of DNS... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-27145 │ +│ ├────────────────┤ │ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-32280 │ │ │ │ 1.25.9, 1.26.2 │ crypto/x509: crypto/tls: golang: Go: Denial of Service │ +│ │ │ │ │ │ │ vulnerability in certificate chain building... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-32280 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-32281 │ │ │ │ │ crypto/x509: golang: Go crypto/x509: Denial of Service via │ +│ │ │ │ │ │ │ inefficient certificate chain validation... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-32281 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-32283 │ │ │ │ │ crypto/tls: golang: Go crypto/tls: Denial of Service via │ +│ │ │ │ │ │ │ multiple TLS 1.3 key... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-32283 │ +│ ├────────────────┤ │ │ ├──────────────────────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-33811 │ │ │ │ 1.25.10, 1.26.3 │ net: golang: Go net package: Denial of Service via long │ +│ │ │ │ │ │ │ CNAME response... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-33811 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-33814 │ │ │ │ │ net/http/internal/http2: golang: golang.org/x/net: Go │ +│ │ │ │ │ │ │ HTTP/2: Denial of Service via malformed │ +│ │ │ │ │ │ │ SETTINGS_MAX_FRAME_SIZE frame... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-33814 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-39820 │ │ │ │ │ net/mail: golang: Go net/mail: Denial of Service via crafted │ +│ │ │ │ │ │ │ email inputs │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-39820 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-39836 │ │ │ │ │ ELSA-2026-22121: golang security update (IMPORTANT) │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-39836 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2026-42499 │ │ │ │ │ net/mail: golang: net/mail: Denial of Service via │ +│ │ │ │ │ │ │ pathological email address parsing │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2026-42499 │ +└─────────┴────────────────┴──────────┴────────┴───────────────────┴──────────────────────────────┴──────────────────────────────────────────────────────────────┘ +``` + +``` +trivy fs . --severity HIGH,CRITICAL +2026-07-03T23:41:08+03:00 INFO [vuln] Vulnerability scanning is enabled +2026-07-03T23:41:08+03:00 INFO [secret] Secret scanning is enabled +2026-07-03T23:41:08+03:00 INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning +2026-07-03T23:41:08+03:00 INFO [secret] Please see https://trivy.dev/docs/v0.72/guide/scanner/secret#recommendation for faster secret detection +2026-07-03T23:41:08+03:00 INFO Number of language-specific files num=1 +2026-07-03T23:41:08+03:00 INFO [gomod] Detecting vulnerabilities... + +Report Summary + +┌──────────────────────────────────────────────────┬───────┬─────────────────┬─────────┐ +│ Target │ Type │ Vulnerabilities │ Secrets │ +├──────────────────────────────────────────────────┼───────┼─────────────────┼─────────┤ +│ app/go.mod │ gomod │ 0 │ - │ +├──────────────────────────────────────────────────┼───────┼─────────────────┼─────────┤ +│ .vagrant/machines/default/virtualbox/private_key │ text │ - │ 1 │ +└──────────────────────────────────────────────────┴───────┴─────────────────┴─────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + + +.vagrant/machines/default/virtualbox/private_key (secrets) + +Total: 1 (HIGH: 1, CRITICAL: 0) + +HIGH: AsymmetricPrivateKey (private-key) +═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ +Asymmetric Private Key +───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + .vagrant/machines/default/virtualbox/private_key:2-7 (offset: 36 bytes) +───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + 1 -----BEGIN OPENSSH PRIVATE KEY----- + 2 ┌ ************************************************************ + 3 │ ************************************************************ + 4 │ ************************************************************ + 5 │ ************************************************************ + 6 │ ************************************************************ + 7 └ ************************ + 8 -----END OPENSSH PRIVATE KEY----- +───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +``` + +``` +trivy config . +2026-07-03T23:43:25+03:00 INFO [misconfig] Misconfiguration scanning is enabled +2026-07-03T23:43:25+03:00 INFO [checks-client] Using existing checks from cache path="/home/long1tail/.cache/trivy/policy/content" +2026-07-03T23:43:26+03:00 INFO Detected config files num=1 + +Report Summary + +┌────────────────┬────────────┬───────────────────┐ +│ Target │ Type │ Misconfigurations │ +├────────────────┼────────────┼───────────────────┤ +│ app/Dockerfile │ dockerfile │ 1 │ +└────────────────┴────────────┴───────────────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + + +app/Dockerfile (dockerfile) + +Tests: 27 (SUCCESSES: 26, FAILURES: 1) +Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) + +DS-0026 (LOW): Add HEALTHCHECK instruction in your Dockerfile +═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ +You should add HEALTHCHECK instruction in your docker container images to perform the health check on running containers. + +See https://avd.aquasec.com/misconfig/ds-0026 +───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── +``` + +``` +2026-07-03T23:48:16+03:00 INFO "--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the "cyclonedx" report. +2026-07-03T23:48:16+03:00 INFO Detected OS family="debian" version="13.5" +2026-07-03T23:48:16+03:00 INFO Number of language-specific files num=1 +{ + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7", + "serialNumber": "urn:uuid:5cfb98d0-5b0a-4f53-a8c8-6c125b427428", + "version": 1, + "metadata": { + "timestamp": "2026-07-03T20:48:16+00:00", + "tools": { + "components": [ + { + "type": "application", + "manufacturer": { + "name": "Aqua Security Software Ltd." + }, + "group": "aquasecurity", + "name": "trivy", + "version": "0.72.0" + } + ] + }, + "component": { + "bom-ref": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "type": "container", + "name": "quicknotes:lab6", + "purl": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:187cfc6d1e3e8a40a5e64653bcd3239c140807dcf1c09e48021178705a5a6139" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:275a30dd8ce958b21daa9ad962c6fbc09f98306ee2f486b65c9075dc257b1412" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:4cde6b0bb6f50a5f255eef7b2a42162c661cf776b803225dcac9a659e396bb6b" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:4d049f83d9cf21d1f5cc0e11deaf36df02790d0e60c1a3829538fb4b61685368" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:5892e2ebce362e40d2093eb8a7e460aa390423bf3a948d509edad0a1d413e508" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:5fd2536c39c0700be8b7b4344e375196da2f126842fd8ede66996a18860a3890" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:621c35e751a51a9a9dc3e80aa0b7fe8be2a93402ea6ccd307d30852cd7776cda" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:6f1cdceb6a3146f0ccb986521156bef8a422cdbb0863396f7f751f575ba308f4" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:92cb9c37b7d3957ac56645a979418f65e6c5bdba00eb99622affae5fc124ac07" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:ad51d0769d16ba578106a177987dfe3d2e02c1668c852b795b2f6b024068242a" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:af5aa97ebe6ce1604747ec1e21af7136ded391bcabe4acef882e718a87c86bcc" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:bd3cdfae1d3fdd83a2231d608969b38b82349777c2fff9a7c12d54f8ac5c9b38" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:bec7e6bb35e05d1284f28b10d2150c259717d91c658c4c10c08424bb9466caba" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:c8b007d0206e4b10ed4d3b3d99dfeab47c2648e82011989fd78a5731baf33fc3" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:ImageID", + "value": "sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3" + }, + { + "name": "aquasecurity:trivy:Reference", + "value": "quicknotes:lab6" + }, + { + "name": "aquasecurity:trivy:RepoDigest", + "value": "quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3" + }, + { + "name": "aquasecurity:trivy:RepoTag", + "value": "quicknotes:lab6" + }, + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + }, + { + "name": "aquasecurity:trivy:Size", + "value": "9106944" + } + ] + } + }, + "components": [ + { + "bom-ref": "ac18a7de-caad-4e7b-8f39-341e712a77fe", + "type": "operating-system", + "name": "debian", + "version": "13.5", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "debian" + } + ] + }, + { + "bom-ref": "f46773e4-a1f6-4360-8501-256ecf13d422", + "type": "application", + "name": "quicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Santiago Vila " + }, + "name": "base-files", + "version": "13.8+deb13u5", + "licenses": [ + { + "license": { + "id": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "verbatim" + } + } + ], + "purl": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:92cb9c37b7d3957ac56645a979418f65e6c5bdba00eb99622affae5fc124ac07" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:47de5dd0b812c573630914955e26abda537e09b5286a824c96e22e3854d4dd53" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "base-files@13.8+deb13u5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "base-files" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "13.8+deb13u5" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Mime-Support Packagers " + }, + "name": "media-types", + "version": "13.0.0", + "licenses": [ + { + "license": { + "name": "ad-hoc" + } + } + ], + "purl": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:275a30dd8ce958b21daa9ad962c6fbc09f98306ee2f486b65c9075dc257b1412" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:d6b1b89eccacc15c2420b2776d72c1dae334a00805ed9af54bf2f71e4d536f28" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "media-types@13.0.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "media-types" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "13.0.0" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "Marco d'Itri " + }, + "name": "netbase", + "version": "6.5", + "licenses": [ + { + "license": { + "id": "GPL-2.0-only" + } + } + ], + "purl": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:621c35e751a51a9a9dc3e80aa0b7fe8be2a93402ea6ccd307d30852cd7776cda" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:c172f21841dff4c8cf45cde46589c1c2616cefe7e819965e92e6d3475c428aa0" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "netbase@6.5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "netbase" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "6.5" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "GNU Libc Maintainers " + }, + "name": "tzdata-legacy", + "version": "2026b-0+deb13u1", + "licenses": [ + { + "license": { + "name": "public-domain" + } + } + ], + "purl": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:bec7e6bb35e05d1284f28b10d2150c259717d91c658c4c10c08424bb9466caba" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:99ba982a9142213c751a1709dcf088e63d8601f03b3f211bae037be698fef270" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "tzdata-legacy@2026b-0+deb13u1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "tzdata" + }, + { + "name": "aquasecurity:trivy:SrcRelease", + "value": "0+deb13u1" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2026b" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "type": "library", + "supplier": { + "name": "GNU Libc Maintainers " + }, + "name": "tzdata", + "version": "2026b-0+deb13u1", + "licenses": [ + { + "license": { + "name": "public-domain" + } + } + ], + "purl": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:c8b007d0206e4b10ed4d3b3d99dfeab47c2648e82011989fd78a5731baf33fc3" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:99515e7b4d35e0652d3b0fde571b6ec269222ecacc506f026e1758d6261e9109" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "tzdata@2026b-0+deb13u1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "tzdata" + }, + { + "name": "aquasecurity:trivy:SrcRelease", + "value": "0+deb13u1" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2026b" + } + ] + }, + { + "bom-ref": "pkg:golang/quicknotes", + "type": "library", + "name": "quicknotes", + "purl": "pkg:golang/quicknotes", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:aa0574b2f7185ab28e65d536c216699d8eeb45d74924214e26efae7f53e01e4f" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "quicknotes" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/stdlib@v1.24.5", + "type": "library", + "name": "stdlib", + "version": "v1.24.5", + "purl": "pkg:golang/stdlib@v1.24.5", + "properties": [ + { + "name": "aquasecurity:trivy:LayerDiffID", + "value": "sha256:f9b720b12c137c381ff66e91fc9d534365b7a7c785f2cc4882d5cbecea93acce" + }, + { + "name": "aquasecurity:trivy:LayerDigest", + "value": "sha256:aa0574b2f7185ab28e65d536c216699d8eeb45d74924214e26efae7f53e01e4f" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "stdlib@v1.24.5" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + } + ], + "dependencies": [ + { + "ref": "ac18a7de-caad-4e7b-8f39-341e712a77fe", + "dependsOn": [ + "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5" + ] + }, + { + "ref": "f46773e4-a1f6-4360-8501-256ecf13d422", + "dependsOn": [ + "pkg:golang/quicknotes" + ] + }, + { + "ref": "pkg:deb/debian/base-files@13.8%2Bdeb13u5?arch=amd64&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/media-types@13.0.0?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/netbase@6.5?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/tzdata-legacy@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/tzdata@2026b-0%2Bdeb13u1?arch=all&distro=debian-13.5", + "dependsOn": [] + }, + { + "ref": "pkg:golang/quicknotes", + "dependsOn": [ + "pkg:golang/stdlib@v1.24.5" + ] + }, + { + "ref": "pkg:golang/stdlib@v1.24.5", + "dependsOn": [] + }, + { + "ref": "pkg:oci/quicknotes@sha256:7cb3a02c11cf2ff470db3d1a9424b5b504d22a78cf0a33e541054e06c0c383b3?arch=amd64&repository_url=index.docker.io%2Flibrary%2Fquicknotes", + "dependsOn": [ + "ac18a7de-caad-4e7b-8f39-341e712a77fe", + "f46773e4-a1f6-4360-8501-256ecf13d422" + ] + } + ], + "vulnerabilities": [] +} +``` + + +| vulnerability | label | reason | +|---------------|-------|--------| +| CVE-2025-68121 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2025-61726 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2025-61729 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-25679 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-27145 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-32280 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-32281 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-32283 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-33811 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-33814 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-39820 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-39836 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| CVE-2026-42499 | FALSE POSITIVE | `go run golang.org/x/vuln/cmd/govulncheck@latest ./...` showed `go run golang.org/x/vuln/cmd/govulncheck@latest ./...`, therefore I assume that no vulnerable functions were executed | +| HIGH: AsymmetricPrivateKey (private-key) | FALSE POSITIVE | 1. .vagrant folder is totaly local. It is included in .gitignore. Therefore, this key is not exposed. 2. Every `vagrant up` will re-generate this key, so even if it is exposed, next `vagrant up` will fix it (if not already) | + +- a. Severity is just the starting point. Reachability (does my code even call the vulnerable function?) is the real filter. Exploit availability (PoC, wormable?) and deployment context (internet-facing vs internal, network isolation) also should be kept in mind before making any desicion +- b. Distroless strips out OS package managers, shells, and tools. Therefore, there’s literally nothing to patch except your own app. No bash, no apt, no curl, no attack surface for dependency confusion or misconfigured package repos. It forces you to ship only what you compiled, making vulnerabilities in the base image a non-issue. +- c. `.trivyignore` is the right move for false positives or local dev artifacts (like the Vagrant key) that never touch prod—saves noise. It becomes security theater when you silence real findings without understanding them, just to pass a CI check. If you can’t justify it, you’re just hiding the problem. +- d. SBOM today means when the next Log4Shell drops, you can instantly `grep` your SBOM for that library across every image and service, instead of manually checking each Dockerfile or trusting memory. It turns an emergency fire drill into a 5-minute query, and you know exactly which versions need upgrading. + +### Task 2 + +I run zap via `docker run --rm --network host -v "$(pwd)/submissions:/zap/wrk" ghcr.io/zaproxy/zaproxy:2.16.1 zap-baseline.py -t http://localhost:8080 -r zap-baseline-before.html -J zap-baseline-before.json` + + +| Alert ID | Finding Name | Risk Level | Affected URL / Parameter | Disposition | Reasoning / Mitigation Strategy | +------------------------------------------------------------------------------------------------------------------- +| 10116 | ZAP is Out of Date | Low | http://localhost:8080 | SUPPRESS | It just says that I'm using old zap version. I'll rerun with newer one | +| 10049 | Storable and Cacheable Content | Informational | http://localhost:8080, http://localhost:8080/robots.txt, http://localhost:8080/sitemap.xml | SUPPRESS | Changing dynamic endpoints may cause data leackage. Added `SecurityHeaders` func to headers.go | + +#### How patched: + + +In `handlers.go`: +``` +func SecurityHeaders(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("Cross-Origin-Resource-Policy", "same-origin") + w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("X-Frame-Options", "DENY") + w.Header().Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'") + + next.ServeHTTP(w, r) + }) +} + +func (s *Server) Routes() http.Handler { + mux := http.NewServeMux() + mux.HandleFunc("GET /health", s.wrap(s.handleHealth)) + mux.HandleFunc("GET /metrics", s.wrap(s.handleMetrics)) + mux.HandleFunc("GET /notes", s.wrap(s.handleListNotes)) + mux.HandleFunc("POST /notes", s.wrap(s.handleCreateNote)) + mux.HandleFunc("GET /notes/{id}", s.wrap(s.handleGetNote)) + mux.HandleFunc("DELETE /notes/{id}", s.wrap(s.handleDeleteNote)) + return SecurityHeaders(mux) +} +``` + +Zap scans: + +[before](./artifacts%20lab%209/zap-baseline-before.html) + +[after](./artifacts%20lab%209/zap-baseline-after.html) + +- e. It's faster, easier and more reliable. You do not violate DRY principlr. You apply it to every handler and not afraid to forget one +- f. On a regular website, it would block all scripts, styles, and images, turning the page into a blank spot, but for a JSON API, it's ideal, since the API only returns raw data and shouldn't execute any front-end code. +- g. By disabling alerts indiscriminately, you risk accidentally silencing a critical vulnerability (for example, caching a personal account instead of a public file) and turning security into a dangerous illusion. \ No newline at end of file