- C1: Replace all ClickHouse string interpolation with parameterized queries
(query_params) to eliminate SQL injection in analytics endpoints
- C3: Strip Caddy placeholder patterns from redirect rules, protected paths,
and Authentik auth endpoint to prevent config injection
- C4: Replace WAF custom directive blocklist with allowlist approach — only
SecRule/SecAction/SecMarker/SecDefaultAction permitted; block ctl:ruleEngine
and Include directives
- H2: Validate GCM authentication tag is exactly 16 bytes before decryption
- H3: Validate forward auth redirect URIs (scheme, no credentials) to prevent
open redirects
- H4: Switch 11 analytics/WAF/geoip endpoints from session-only requireAdmin
to requireApiAdmin supporting both Bearer token and session auth
- H5: Add input validation for instance-mode (whitelist) and sync-token
(32-char minimum) in settings API
- M1: Add non-root user to l4-port-manager Dockerfile
- M5: Document Caddy admin API binding security rationale
- Document C2 (custom config injection) and H1 (SSRF via upstreams) as
intentional admin features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- C1: Replace all ClickHouse string interpolation with parameterized queries
(query_params) to eliminate SQL injection in analytics endpoints
- C3: Strip Caddy placeholder patterns from redirect rules, protected paths,
and Authentik auth endpoint to prevent config injection
- C4: Replace WAF custom directive blocklist with allowlist approach — only
SecRule/SecAction/SecMarker/SecDefaultAction permitted; block ctl:ruleEngine
and Include directives
- H2: Validate GCM authentication tag is exactly 16 bytes before decryption
- H3: Validate forward auth redirect URIs (scheme, no credentials) to prevent
open redirects
- H4: Switch 11 analytics/WAF/geoip endpoints from session-only requireAdmin
to requireApiAdmin supporting both Bearer token and session auth
- H5: Add input validation for instance-mode (whitelist) and sync-token
(32-char minimum) in settings API
- M1: Add non-root user to l4-port-manager Dockerfile
- M5: Document Caddy admin API binding security rationale
- Document C2 (custom config injection) and H1 (SSRF via upstreams) as
intentional admin features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New l4_proxy_hosts table and Drizzle migration (0015)
- Full CRUD model layer with validation, audit logging, and Caddy config
generation (buildL4Servers integrating into buildCaddyDocument)
- Server actions, paginated list page, create/edit/delete dialogs
- L4 port manager sidecar (docker/l4-port-manager) that auto-recreates
the caddy container when port mappings change via a trigger file
- Auto-detects Docker Compose project name from caddy container labels
- Supports both named-volume and bind-mount (COMPOSE_HOST_DIR) deployments
- getL4PortsStatus simplified: status file is sole source of truth,
trigger files deleted after processing to prevent stuck 'Waiting' banner
- Navigation entry added (CableIcon)
- Tests: unit (entrypoint.sh invariants + validation), integration (ports
lifecycle + caddy config), E2E (CRUD + functional routing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>