You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(security): require ADMIN_PASSWORD instead of logging a generated one
CodeQL go/clear-text-logging (high) flagged logging the generated admin
password. Logging a secret is a real leak (logs get shipped and read), so
remove it: when authentication is enabled the server now requires
ADMIN_PASSWORD and fails closed if it is unset, rather than seeding a
well-known password or logging a generated one. When authentication is
disabled (development) a random, unlogged password is seeded since it gates
nothing. Compose now requires ADMIN_PASSWORD via ${ADMIN_PASSWORD:?}; docs and
the k8s secret template are updated to match.
|`AUTH_SECRETKEY`| JWT signing key. Required in release mode; must be a strong random value of at least 32 bytes | none |
18
-
|`ADMIN_PASSWORD`| Initial admin password. If unset, a random one is generated and printed once at first boot| none |
18
+
|`ADMIN_PASSWORD`| Initial admin password. Required on first boot when `AUTH_ENABLED=true`; the server will not seed a well-known password or log a generated one| none |
19
19
|`CORS_ALLOWED_ORIGINS`| Comma-separated allowed browser origins, or `*` for any |`*`|
Copy file name to clipboardExpand all lines: docs/security.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,7 +38,7 @@ a remediation note.
38
38
| Sev | Finding | Fix |
39
39
|-----|---------|-----|
40
40
| Critical | JWT signing key was effectively unconfigurable and defaulted to a public placeholder; `docker-compose.yml` also hardcoded a public key as a literal, and the documented `.env` override was silently ignored. Anyone could forge an admin token offline. | Root cause was a Viper misconfiguration: nested keys (`auth.secretkey`) were never bound to env vars (`AUTH_SECRETKEY`), so every environment override was dropped. Added `SetEnvKeyReplacer` plus explicit `BindEnv` for all keys. Added a fail-closed guard that refuses to start in release mode on any known placeholder key or a key shorter than 32 bytes. `docker-compose.yml` now uses `${AUTH_SECRETKEY:?}` so Compose aborts when it is unset. `k8s/secret.yaml` ships with no value and documents out-of-band creation. `.env.example` blanks the key. Regression tests cover the env-override path and the guard. |
41
-
| High | Default admin account `admin/admin123` was auto-created on first boot; no deployment path set `ADMIN_PASSWORD`. |If `ADMIN_PASSWORD` is unset, the server now generates a strong random password with `crypto/rand`and logs it once at first boot. The well-known fallback is gone. |
41
+
| High | Default admin account `admin/admin123` was auto-created on first boot; no deployment path set `ADMIN_PASSWORD`. |When authentication is enabled, the server now requires `ADMIN_PASSWORD` and fails closed if it is unset - it never seeds a well-known password and never logs a generated one (logging a secret is itself a leak, flagged by CodeQL `go/clear-text-logging`). When authentication is disabled (development), a random unlogged password is seeded since it gates nothing. |
42
42
| High | A committed key in `k8s/secret.yaml` was applied by the documented deploy command. | Value removed; the manifest documents `kubectl create secret` from a generated value. |
43
43
| High | Unauthenticated mirror-protocol routes spawned one unbounded background upstream download per request (disk/bandwidth amplification DoS). | Background caching is now bounded by a semaphore (max 3 concurrent) and deduped by an in-flight set, launched via `tryStartBackgroundCache`. A burst degrades to "cached on a later request" instead of spawning unbounded goroutines. The routes stay unauthenticated so the Terraform network mirror keeps working. |
44
44
| Medium | The role claim was never enforced: `RequireRole` was applied to zero routes, so any authenticated principal was fully privileged. | Write/management routes are now behind an admin group (`AuthMiddleware` + `RequireRole("admin")`). `/auth/me` stays at authenticated-only. Verified: a valid non-admin token gets 403 on writes. |
0 commit comments