PR #3 of the 11-PR completion sequence. Addresses the two highest-severity findings in the repo review:
NewServer silently falling back to a per-process ephemeral JWT secret (or a predictable time-based one on rand.Read error).
A default Content-Security-Policy that shipped 'unsafe-inline', 'unsafe-eval', and the private 192.168.11.x RPC CIDRs to every visitor.
It also removes hardcoded L@kers2010 / L@ker$2010 defaults from 7 helper scripts + 2 top-level EXECUTE_*.sh runners and the README.md / docs/DEPLOYMENT.md operator tables, and introduces docs/SECURITY.md with the rotation checklist.
CSP_HEADER is required in production (fatal on startup if unset).
Hardcoded password removal
All 9 occurrences of L@kers2010 / L@ker$2010 that live in tracked files other than the three docs being deleted by PR #2 (START_HERE.md, LETSENCRYPT_CONFIGURATION_GUIDE.md) are gone:
scripts/analyze-besu-logs.sh, scripts/check-besu-config.sh, scripts/check-besu-logs-with-password.sh, scripts/check-failed-transaction-details.sh, scripts/enable-besu-debug-api.sh, scripts/set-vmid-password.sh, scripts/set-vmid-password-correct.sh — SSH_PASSWORD/NEW_PASSWORD now required via env or argv; fail-fast with exit 2 pointing at docs/SECURITY.md.
EXECUTE_DEPLOYMENT.sh, EXECUTE_NOW.sh — DB_PASSWORD (and RPC_URL) are now :? guarded.
README.md — hardcoded Database Password: L@ker$2010 replaced with an env-variable reference table.
docs/DEPLOYMENT.md — PASSWORD: SSH password (default: L@kers2010) replaced with "required; no default".
New docs/SECURITY.md
Full inventory keyed by env variable name ↔ consuming file.
Five-step rotation checklist (Postgres role, VM SSH password, JWT_SECRET, vendor API keys, gitleaks history audit).
Explicit note that merging scrub PRs does not invalidate previously leaked credentials — rotation is still required.
go test ./api/rest/ -run 'LoadJWTSecret|IsProduction|DefaultDevCSP' — passes.
Grep L@kers\?2010\|L@ker\$2010 across all *.sh, *.go, *.yml, *.yaml, *.md — only remaining hits are in START_HERE.md and LETSENCRYPT_CONFIGURATION_GUIDE.md, which are deleted by PR #2.
Completion criterion advanced
2. Secrets & config hardened — "JWT_SECRET is fatal on missing/short value in prod; CSP excludes unsafe-* and private CIDRs; no passwords hardcoded in scripts or docs."
Still outstanding: rotation of the leaked credentials (operator-side, tracked in docs/SECURITY.md) and gitleaks CI wiring (PR #5).
## Summary
PR #3 of the 11-PR completion sequence. Addresses the two highest-severity findings in the repo review:
1. `NewServer` silently falling back to a per-process ephemeral JWT secret (or a predictable time-based one on `rand.Read` error).
2. A default `Content-Security-Policy` that shipped `'unsafe-inline'`, `'unsafe-eval'`, and the private `192.168.11.x` RPC CIDRs to every visitor.
It also removes hardcoded `L@kers2010` / `L@ker$2010` defaults from 7 helper scripts + 2 top-level `EXECUTE_*.sh` runners and the `README.md` / `docs/DEPLOYMENT.md` operator tables, and introduces `docs/SECURITY.md` with the rotation checklist.
## JWT secret loading
<ref_snippet file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server.go" lines="66-92" />
- `JWT_SECRET` must be ≥32 bytes; otherwise `log.Fatal`.
- `JWT_SECRET` is required when `APP_ENV=production` or `GO_ENV=production`.
- In non-prod we generate 32 bytes from `crypto/rand`. A `rand.Read` failure is now fatal — the previous `ephemeral-jwt-secret-<unix_nano>` fallback is gone.
## CSP hardening
<ref_snippet file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server.go" lines="36-49" />
- `defaultDevCSP` drops `'unsafe-inline'` and `'unsafe-eval'`.
- Drops the private RPC CIDRs.
- Adds `frame-ancestors 'none'`, `base-uri 'self'`, `form-action 'self'`.
- `CSP_HEADER` is required in production (fatal on startup if unset).
## Hardcoded password removal
All 9 occurrences of `L@kers2010` / `L@ker$2010` that live in tracked files other than the three docs being deleted by PR #2 (`START_HERE.md`, `LETSENCRYPT_CONFIGURATION_GUIDE.md`) are gone:
- `scripts/analyze-besu-logs.sh`, `scripts/check-besu-config.sh`, `scripts/check-besu-logs-with-password.sh`, `scripts/check-failed-transaction-details.sh`, `scripts/enable-besu-debug-api.sh`, `scripts/set-vmid-password.sh`, `scripts/set-vmid-password-correct.sh` — `SSH_PASSWORD`/`NEW_PASSWORD` now required via env or argv; fail-fast with `exit 2` pointing at `docs/SECURITY.md`.
- `EXECUTE_DEPLOYMENT.sh`, `EXECUTE_NOW.sh` — `DB_PASSWORD` (and `RPC_URL`) are now `:?` guarded.
- `README.md` — hardcoded `Database Password: L@ker$2010` replaced with an env-variable reference table.
- `docs/DEPLOYMENT.md` — `PASSWORD: SSH password (default: L@kers2010)` replaced with "required; no default".
## New `docs/SECURITY.md`
- Full inventory keyed by env variable name ↔ consuming file.
- Five-step rotation checklist (Postgres role, VM SSH password, `JWT_SECRET`, vendor API keys, gitleaks history audit).
- Explicit note that merging scrub PRs does **not** invalidate previously leaked credentials — rotation is still required.
## Tests
<ref_file file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server_security_test.go" />
- `TestLoadJWTSecretAcceptsSufficientlyLongValue`
- `TestLoadJWTSecretStripsSurroundingWhitespace`
- `TestLoadJWTSecretGeneratesEphemeralInDevelopment` (asserts the new ephemeral secret does NOT start with the old `ephemeral-jwt-secret-` prefix)
- `TestIsProductionEnv` (7 cases)
- `TestDefaultDevCSPHasNoUnsafeDirectivesOrPrivateCIDRs`
## Verification
- `go build ./...` — clean.
- `go vet ./...` — clean.
- `go test ./api/rest/ -run 'LoadJWTSecret|IsProduction|DefaultDevCSP'` — passes.
- Grep `L@kers\?2010\|L@ker\$2010` across all `*.sh`, `*.go`, `*.yml`, `*.yaml`, `*.md` — only remaining hits are in `START_HERE.md` and `LETSENCRYPT_CONFIGURATION_GUIDE.md`, which are deleted by [PR #2](https://gitea.d-bis.org/d-bis/explorer-monorepo/pulls/2).
## Completion criterion advanced
> **2. Secrets & config hardened** — "JWT_SECRET is fatal on missing/short value in prod; CSP excludes `unsafe-*` and private CIDRs; no passwords hardcoded in scripts or docs."
Still outstanding: rotation of the leaked credentials (operator-side, tracked in `docs/SECURITY.md`) and gitleaks CI wiring (PR #5).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
PR #3 of the 11-PR completion sequence. Addresses the two highest-severity findings in the repo review:
NewServersilently falling back to a per-process ephemeral JWT secret (or a predictable time-based one onrand.Readerror).Content-Security-Policythat shipped'unsafe-inline','unsafe-eval', and the private192.168.11.xRPC CIDRs to every visitor.It also removes hardcoded
L@kers2010/L@ker$2010defaults from 7 helper scripts + 2 top-levelEXECUTE_*.shrunners and theREADME.md/docs/DEPLOYMENT.mdoperator tables, and introducesdocs/SECURITY.mdwith the rotation checklist.JWT secret loading
<ref_snippet file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server.go" lines="66-92" />
JWT_SECRETmust be ≥32 bytes; otherwiselog.Fatal.JWT_SECRETis required whenAPP_ENV=productionorGO_ENV=production.crypto/rand. Arand.Readfailure is now fatal — the previousephemeral-jwt-secret-<unix_nano>fallback is gone.CSP hardening
<ref_snippet file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server.go" lines="36-49" />
defaultDevCSPdrops'unsafe-inline'and'unsafe-eval'.frame-ancestors 'none',base-uri 'self',form-action 'self'.CSP_HEADERis required in production (fatal on startup if unset).Hardcoded password removal
All 9 occurrences of
L@kers2010/L@ker$2010that live in tracked files other than the three docs being deleted by PR #2 (START_HERE.md,LETSENCRYPT_CONFIGURATION_GUIDE.md) are gone:scripts/analyze-besu-logs.sh,scripts/check-besu-config.sh,scripts/check-besu-logs-with-password.sh,scripts/check-failed-transaction-details.sh,scripts/enable-besu-debug-api.sh,scripts/set-vmid-password.sh,scripts/set-vmid-password-correct.sh—SSH_PASSWORD/NEW_PASSWORDnow required via env or argv; fail-fast withexit 2pointing atdocs/SECURITY.md.EXECUTE_DEPLOYMENT.sh,EXECUTE_NOW.sh—DB_PASSWORD(andRPC_URL) are now:?guarded.README.md— hardcodedDatabase Password: L@ker$2010replaced with an env-variable reference table.docs/DEPLOYMENT.md—PASSWORD: SSH password (default: L@kers2010)replaced with "required; no default".New
docs/SECURITY.mdJWT_SECRET, vendor API keys, gitleaks history audit).Tests
<ref_file file="/home/ubuntu/repos/explorer-monorepo/backend/api/rest/server_security_test.go" />
TestLoadJWTSecretAcceptsSufficientlyLongValueTestLoadJWTSecretStripsSurroundingWhitespaceTestLoadJWTSecretGeneratesEphemeralInDevelopment(asserts the new ephemeral secret does NOT start with the oldephemeral-jwt-secret-prefix)TestIsProductionEnv(7 cases)TestDefaultDevCSPHasNoUnsafeDirectivesOrPrivateCIDRsVerification
go build ./...— clean.go vet ./...— clean.go test ./api/rest/ -run 'LoadJWTSecret|IsProduction|DefaultDevCSP'— passes.L@kers\?2010\|L@ker\$2010across all*.sh,*.go,*.yml,*.yaml,*.md— only remaining hits are inSTART_HERE.mdandLETSENCRYPT_CONFIGURATION_GUIDE.md, which are deleted by PR #2.Completion criterion advanced
Still outstanding: rotation of the leaked credentials (operator-side, tracked in
docs/SECURITY.md) and gitleaks CI wiring (PR #5).