security: fix 17 vulnerabilities from comprehensive pentest

Fixes identified from full security audit covering auth, crypto,
injection, infrastructure, and configuration security.

Critical:
- C1: Fail-closed on unrecognized NODE_ENV (prevent DEV_SECRET in staging)
- C3: Validate API token expires_at (reject invalid dates that bypass expiry)

High:
- H1: Refresh JWT role from DB on each session (reflect demotions immediately)
- H2: Docker socket proxy for l4-port-manager (restrict API surface)
- H5: Block dangerous WAF custom directives (SecRuleEngine, SecAuditEngine)
- H7: Require explicit NEXTAUTH_TRUST_HOST instead of always trusting Host
- H8: Semantic validation of sync payload (block metadata SSRF, size limits)

Medium:
- M3: Rate limit password change current-password verification
- M5: Parameterized SQL in log/waf parsers (replace template literals)
- M6: Nonce-based CSP replacing unsafe-inline for script-src
- M9: Strip Caddy placeholders from rewrite path_prefix
- M10: Sanitize authentik outpostDomain (path traversal, placeholders)
- M14: Deny access on missing JWT role instead of defaulting to "user"

Low:
- L1: Require Origin header on mutating session-authenticated requests
- L4: Enforce password complexity on user password changes
- L5: Time-limited legacy SHA-256 key fallback (grace period until 2026-06-01)
- L6: Escape LIKE metacharacters in audit log search
- L7: Runtime-validate WAF excluded_rule_ids as positive integers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-03-26 12:14:44 +01:00
parent 7a12ecf2fe
commit debd0d98fc
18 changed files with 339 additions and 77 deletions
+30 -2
View File
@@ -111,9 +111,33 @@ services:
retries: 3
start_period: 10s
# H2: Docker socket proxy — restricts API surface exposed to l4-port-manager.
# Only allows GET, POST to /containers/ and /compose/ endpoints.
# Prevents container escape via unrestricted Docker API access.
docker-socket-proxy:
container_name: caddy-proxy-manager-docker-proxy
image: tecnativa/docker-socket-proxy:latest
restart: unless-stopped
environment:
CONTAINERS: 1
POST: 1
# Deny everything else by default
IMAGES: 0
NETWORKS: 0
VOLUMES: 0
EXEC: 0
SWARM: 0
AUTH: 0
SECRETS: 0
BUILD: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- caddy-network
# L4 Port Manager sidecar — automatically recreates the caddy container
# when L4 proxy host ports change.
# Requires Docker socket access (read-only) to recreate the caddy container.
# Uses Docker socket proxy instead of direct Docker socket access.
l4-port-manager:
container_name: caddy-proxy-manager-l4-ports
image: ghcr.io/fuomag9/caddy-proxy-manager-l4-port-manager:latest
@@ -125,13 +149,17 @@ services:
DATA_DIR: /data
COMPOSE_DIR: /compose
POLL_INTERVAL: "${L4_PORT_MANAGER_POLL_INTERVAL:-2}"
DOCKER_HOST: tcp://docker-socket-proxy:2375
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- caddy-manager-data:/data
- .:/compose:ro
depends_on:
caddy:
condition: service_healthy
docker-socket-proxy:
condition: service_started
networks:
- caddy-network
geoipupdate:
container_name: geoipupdate-${HOSTNAME}