security-docker

Security audit patterns for Docker and container deployments covering secrets in images, port exposure, user privileges, and compose security.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "security-docker" with this command: npx skills add igorwarzocha/opencode-workflows/igorwarzocha-opencode-workflows-security-docker

Security audit patterns for Docker and container deployments covering secrets in images, port exposure, user privileges, and compose security.

Secrets in Images (Critical)

Secrets in Build Args/ENV

❌ CRITICAL: Secret in ENV (visible in image history)

ENV API_KEY=sk_live_abc123 ENV DATABASE_URL=postgres://user:password@host/db

❌ CRITICAL: Secret in ARG (visible in image history)

ARG AWS_SECRET_ACCESS_KEY RUN aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY

✓ Use runtime secrets

Pass via docker run -e or docker-compose environment/env_file

✓ Docker secrets (Swarm) or orchestrator-specific secrets

Use /run/secrets/* instead of ENV/ARG when available

Secrets Baked into Layers

❌ CRITICAL: Even if deleted, secret is in layer history

COPY .env /app/.env RUN source /app/.env && do_something RUN rm /app/.env # Still in previous layer!

❌ CRITICAL: Copying all files includes secrets

COPY . /app/ # Copies .env, .git, etc.

✓ Use .dockerignore

In .dockerignore:

.env*

.git

*.pem

*.key

✓ Or explicit COPY

COPY package*.json /app/ COPY src/ /app/src/

Checking Image History

Audit existing images for secrets

docker history --no-trunc <image> docker inspect <image> | jq '.[0].Config.Env'

Port Exposure

docker-compose.yml

❌ CRITICAL: Database exposed to host network

services: db: image: postgres ports: - "5432:5432" # Accessible from outside!

❌ CRITICAL: Redis without password

redis: image: redis ports: - "6379:6379" # And no AUTH!

✓ Internal only (accessible to other containers)

services: db: image: postgres expose: - "5432" # Only internal # No 'ports' = not exposed to host

✓ If must expose, bind to localhost

db: ports: - "127.0.0.1:5432:5432" # Only localhost

Default Credentials

❌ No password or default password

services: db: image: postgres environment: POSTGRES_PASSWORD: postgres # Default!

redis: image: redis # No password at all

✓ Strong passwords from secrets

services: db: image: postgres environment: POSTGRES_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password

secrets: db_password: file: ./secrets/db_password.txt # MUST NOT be in git!

Non-Root User

❌ Running as root (default)

FROM node:18 COPY . /app CMD ["node", "server.js"] # Runs as root

✓ Create and use non-root user

FROM node:18 WORKDIR /app COPY --chown=node:node . . USER node CMD ["node", "server.js"]

✓ Using numeric UID (more portable)

FROM node:18 RUN useradd -r -u 1001 appuser WORKDIR /app COPY --chown=1001:1001 . . USER 1001 CMD ["node", "server.js"]

Multi-Stage Builds

❌ Build tools and secrets in final image

FROM node:18 COPY . . RUN npm install RUN npm run build CMD ["node", "dist/server.js"]

Final image has: source, node_modules (dev deps), build tools

✓ Multi-stage: only production artifacts

FROM node:18 AS builder WORKDIR /app COPY package*.json . RUN npm ci COPY . . RUN npm run build

FROM node:18-slim AS production WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules USER node CMD ["node", "dist/server.js"]

Final image: minimal, no source, no build tools

Docker Compose Security

Privileged Mode

❌ CRITICAL: Full host access

services: app: privileged: true # Container can do anything on host!

❌ HIGH: Dangerous capabilities

services: app: cap_add: - SYS_ADMIN - NET_ADMIN

Volume Mounts

❌ CRITICAL: Docker socket access = root on host

services: app: volumes: - /var/run/docker.sock:/var/run/docker.sock

❌ HIGH: Sensitive host paths

services: app: volumes: - /etc:/etc - /root:/root

Network Mode

❌ HIGH: Host network mode

services: app: network_mode: host # Bypasses Docker network isolation

Image Security

Base Image

❌ Outdated or unverified

FROM node:14 # EOL version FROM random-user/node-app # Unverified

✓ Official, recent, minimal

FROM node:20-slim FROM node:20-alpine

Image Scanning

Scan for vulnerabilities

docker scout cves <image> trivy image <image> grype <image>

Quick Audit Commands

Find secrets in Dockerfile

rg "(ENV|ARG).(KEY|SECRET|PASSWORD|TOKEN)" Dockerfile

Find exposed ports in compose

rg "ports:" docker-compose*.yml -A 3

Check for privileged/capabilities

rg "(privileged|cap_add|network_mode)" docker-compose*.yml

Check for docker.sock mount

rg "docker.sock" docker-compose*.yml

Check for USER instruction

grep "^USER" Dockerfile

Check .dockerignore exists and has secrets

cat .dockerignore | grep -E "(env|key|secret|pem)"

Hardening Checklist

  • No secrets in ENV/ARG instructions

  • No secrets COPY'd into image

  • .dockerignore excludes .env, .git, *.pem, *.key

  • Database/Redis ports not exposed to host (or only 127.0.0.1)

  • Strong passwords for all services (not defaults)

  • USER instruction sets non-root user

  • Multi-stage build for production images

  • No privileged: true

  • No docker.sock mount (unless required)

  • Base images are official and recent

  • Images scanned for vulnerabilities

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

security-nextjs

No summary provided by upstream source.

Repository SourceNeeds Review
Security

security-fastapi

No summary provided by upstream source.

Repository SourceNeeds Review
Security

security-express

No summary provided by upstream source.

Repository SourceNeeds Review
Security

security-bun

No summary provided by upstream source.

Repository SourceNeeds Review