Severity: P3 | Subsystem: routing | Category: security
Location: /home/kyleg/containers/atxfpv.org/skwad/Dockerfile:9-15
What
The runtime stage (alpine:3.19) sets no USER, so skwad runs as UID 0. The static binary only needs to read ./static, bind :8080, and access the host-owned /data mount; root is gratuitous and widens RCE blast radius. EXPOSE 8080 is fine.
Suggested fix
adduser -D and USER before CMD; set /data and /app/static perms for that UID.
Verification
Verified against /home/kyleg/containers/atxfpv.org/skwad/Dockerfile. The runtime stage (line 9: FROM alpine:3.19) has no USER directive anywhere (lines 9-15: apk add ca-certificates, WORKDIR /app, COPY binary + static, EXPOSE 8080, CMD ["./skwad"]). grep for USER across the Dockerfile returns nothing. With no USER set, the container runs as UID 0. Confirmed runtime needs in docker-compose.yaml (service skwad, lines 30-58): bind :8080, read STATIC_DIR=/app/static, read/write DB_PATH=/data/skwad.db on the host bind mount ./skwad/data:/data. None require root, so root is gratuitous and the finding's technical claims are all correct.
Severity adjustment: this is a real defense-in-depth hardening gap, not an exploitable vulnerability with a demonstrated path. Single static Go binary behind Traefik on a private host; running as root only matters as RCE blast-radius amplification, which is contingent on a separate RCE that isn't shown. The suggested fix is also not a clean one-liner: the /data mount is a host-owned bind mount, so introducing a non-root USER requires aligning host directory ownership/UID or the SQLite writes break. P2 overstates impact for a generic hardening recommendation with no concrete exploit; P3 is the honest rating.
Filed from the 2026-05-30 multi-agent codebase review.
Severity: P3 | Subsystem: routing | Category: security
Location:
/home/kyleg/containers/atxfpv.org/skwad/Dockerfile:9-15What
The runtime stage (alpine:3.19) sets no USER, so skwad runs as UID 0. The static binary only needs to read ./static, bind :8080, and access the host-owned /data mount; root is gratuitous and widens RCE blast radius. EXPOSE 8080 is fine.
Suggested fix
adduser -D and USER before CMD; set /data and /app/static perms for that UID.
Verification
Verified against /home/kyleg/containers/atxfpv.org/skwad/Dockerfile. The runtime stage (line 9: FROM alpine:3.19) has no USER directive anywhere (lines 9-15: apk add ca-certificates, WORKDIR /app, COPY binary + static, EXPOSE 8080, CMD ["./skwad"]). grep for USER across the Dockerfile returns nothing. With no USER set, the container runs as UID 0. Confirmed runtime needs in docker-compose.yaml (service skwad, lines 30-58): bind :8080, read STATIC_DIR=/app/static, read/write DB_PATH=/data/skwad.db on the host bind mount ./skwad/data:/data. None require root, so root is gratuitous and the finding's technical claims are all correct.
Severity adjustment: this is a real defense-in-depth hardening gap, not an exploitable vulnerability with a demonstrated path. Single static Go binary behind Traefik on a private host; running as root only matters as RCE blast-radius amplification, which is contingent on a separate RCE that isn't shown. The suggested fix is also not a clean one-liner: the /data mount is a host-owned bind mount, so introducing a non-root USER requires aligning host directory ownership/UID or the SQLite writes break. P2 overstates impact for a generic hardening recommendation with no concrete exploit; P3 is the honest rating.
Filed from the 2026-05-30 multi-agent codebase review.