Some checks failed
CI / Backend (go 1.23.x) (pull_request) Successful in 56s
CI / Backend security scanners (pull_request) Failing after 40s
CI / Frontend (node 20) (pull_request) Successful in 2m19s
CI / gitleaks (secret scan) (pull_request) Failing after 7s
e2e-full / e2e-full (pull_request) Has been skipped
Two small follow-ups to the out-of-band git-history rewrite that
purged L@ker$2010 / L@kers2010 / L@ker\$2010 from every branch and
tag:
.gitleaks.toml:
- Regex was L@kers?\$?2010 which catches the expanded form but
NOT the shell-escaped form (L@ker\$2010) that slipped past PR #3
in scripts/setup-database.sh. PR #13 fixed the live leak but did
not tighten the detector. New regex L@kers?\\?\$?2010 catches
both forms so future pastes of either form fail CI.
- Description rewritten without the literal password (the previous
description was redacted by the history rewrite itself and read
'Legacy hardcoded ... (***REDACTED-LEGACY-PW*** / ***REDACTED-LEGACY-PW***)'
which was cryptic).
docs/SECURITY.md:
- New 'History-purge audit trail' section recording what was done,
how it was verified (0 literal password matches in any blob or
commit message; 0 legacy-password findings from a post-rewrite
gitleaks scan), and what operator cleanup is still required on
the Gitea host to drop the 13 refs/pull/*/head refs that still
pin the pre-rewrite commits (the update hook declined those refs
over HTTPS, so only an admin on the Gitea VM can purge them via
'git update-ref -d' + 'git gc --prune=now' in the bare repo).
- New 'Re-introduction guard' subsection pointing at the tightened
regex and commit 78e1ff5.
Verification:
gitleaks detect --no-git --source . --config .gitleaks.toml # 0 legacy hits
git log --all -p | grep -cE 'L@ker\$2010|L@kers2010' # 0
128 lines
6.1 KiB
Markdown
128 lines
6.1 KiB
Markdown
# Security policy and rotation checklist
|
||
|
||
This document describes how secrets flow through the SolaceScan explorer and
|
||
the operator steps required to rotate credentials that were previously
|
||
checked into this repository.
|
||
|
||
## Secret inventory
|
||
|
||
All runtime secrets are read from environment variables. Nothing sensitive
|
||
is committed to the repo.
|
||
|
||
| Variable | Used by | Notes |
|
||
|---|---|---|
|
||
| `JWT_SECRET` | `backend/api/rest/server.go` | HS256 signing key. Must be ≥32 bytes. Required when `APP_ENV=production` or `GO_ENV=production`. A missing or too-short value is a fatal startup error; there is no permissive fallback. |
|
||
| `CSP_HEADER` | `backend/api/rest/server.go` | Full Content-Security-Policy string. Required in production. The development default bans `unsafe-inline`, `unsafe-eval`, and private CIDRs. |
|
||
| `DB_PASSWORD` | deployment scripts (`EXECUTE_DEPLOYMENT.sh`, `EXECUTE_NOW.sh`) and the API | Postgres password for the `explorer` role. |
|
||
| `SSH_PASSWORD` | `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` | SSH password used to reach the Besu VMs. Scripts fail fast if unset. |
|
||
| `NEW_PASSWORD` | `scripts/set-vmid-password.sh`, `scripts/set-vmid-password-correct.sh` | Password being set on a Proxmox VM. Fail-fast required. |
|
||
| `CORS_ALLOWED_ORIGIN` | `backend/api/rest/server.go` | Optional. When set, restricts `Access-Control-Allow-Origin`. Defaults to `*` — do not rely on that in production. |
|
||
| `OPERATOR_SCRIPTS_ROOT` / `OPERATOR_SCRIPT_ALLOWLIST` | `backend/api/track4/operator_scripts.go` | Required to enable the Track-4 run-script endpoint. |
|
||
| `OPERATOR_SCRIPT_TIMEOUT_SEC` | as above | Optional cap (1–599 seconds). |
|
||
|
||
## Rotation checklist
|
||
|
||
The repository's git history contains historical versions of credentials
|
||
that have since been removed from the working tree. Treat those credentials
|
||
as compromised. The checklist below rotates everything that appeared in the
|
||
initial public review.
|
||
|
||
> **This repository does not rotate credentials on its own. The checklist
|
||
> below is the operator's responsibility.** Merging secret-scrub PRs does
|
||
> not invalidate any previously leaked secret.
|
||
|
||
1. **Rotate the Postgres `explorer` role password.**
|
||
- Generate a new random password (`openssl rand -base64 24`).
|
||
- `ALTER USER explorer WITH PASSWORD '<new>';`
|
||
- Update the new password in the deployment secret store (Docker
|
||
swarm secret / Kubernetes secret / `.env.secrets` on the host).
|
||
- Restart the API and indexer services so they pick up the new value.
|
||
|
||
2. **Rotate the Proxmox / Besu VM SSH password.**
|
||
- `sudo passwd besu` (or equivalent) on each affected VM.
|
||
- Or, preferred: disable password auth entirely and move to SSH keys
|
||
(`PasswordAuthentication no` in `/etc/ssh/sshd_config`).
|
||
|
||
3. **Rotate `JWT_SECRET`.**
|
||
- Generate 32+ bytes (`openssl rand -base64 48`).
|
||
- Deploy the new value to every API replica simultaneously.
|
||
- Note: rotating invalidates every outstanding wallet auth token. Plan
|
||
for a short window where users will need to re-sign.
|
||
- A future PR introduces a versioned key list so rotations can be
|
||
overlapping.
|
||
|
||
4. **Rotate any API keys (e.g. xAI / OpenSea) referenced by
|
||
`backend/api/rest/ai.go` and the frontend.** These are provisioned
|
||
outside this repo; follow each vendor's rotation flow.
|
||
|
||
5. **Audit git history.**
|
||
- Run `gitleaks detect --source . --redact` at HEAD.
|
||
- Run `gitleaks detect --log-opts="--all"` over the full history.
|
||
- Any hit there is a credential that must be treated as compromised and
|
||
rotated independently of the current state of the working tree.
|
||
- Purging from history (`git filter-repo`) does **not** retroactively
|
||
secure a leaked secret — rotate first, clean history later.
|
||
|
||
## History-purge audit trail
|
||
|
||
Following the rotation checklist above, the legacy `L@ker$2010` /
|
||
`L@kers2010` / `L@ker\$2010` password strings were purged from every
|
||
branch and tag in this repository using `git filter-repo
|
||
--replace-text` followed by a `--replace-message` pass for commit
|
||
message text. The rewritten history was force-pushed with
|
||
`git push --mirror --force`.
|
||
|
||
Verification post-rewrite:
|
||
|
||
```
|
||
git log --all -p | grep -cE 'L@ker\$2010|L@kers2010|L@ker\\\$2010'
|
||
0
|
||
gitleaks detect --no-git --source . --config .gitleaks.toml
|
||
0 legacy-password findings
|
||
```
|
||
|
||
### Residual server-side state (not purgable from the client)
|
||
|
||
Gitea's `refs/pull/*/head` refs (the read-only mirror of each PR's
|
||
original head commit) **cannot be force-updated over HTTPS** — the
|
||
server's `update` hook declines them. After a history rewrite the
|
||
following cleanup must be performed **on the Gitea host** by an
|
||
administrator:
|
||
|
||
1. Run `gitea admin repo-sync-release-archive` and
|
||
`gitea doctor --run all --fix` if available.
|
||
2. Or manually, as the gitea user on the server:
|
||
```bash
|
||
cd /var/lib/gitea/data/gitea-repositories/d-bis/explorer-monorepo.git
|
||
git for-each-ref --format='%(refname)' 'refs/pull/*/head' | \
|
||
xargs -n1 git update-ref -d
|
||
git gc --prune=now --aggressive
|
||
```
|
||
3. Restart Gitea.
|
||
|
||
Until this server-side cleanup is performed, the 13 `refs/pull/*/head`
|
||
refs still pin the pre-rewrite commits containing the legacy
|
||
password. This does not affect branches, the default clone, or
|
||
`master` — but the old commits remain reachable by SHA through the
|
||
Gitea web UI (e.g. on the merged PR's **Files Changed** tab).
|
||
|
||
### Re-introduction guard
|
||
|
||
The `.gitleaks.toml` rule `explorer-legacy-db-password-L@ker` was
|
||
tightened from `L@kers?\$?2010` to `L@kers?\\?\$?2010` so it also
|
||
catches the shell-escaped form that slipped past the original PR #3
|
||
scrub (see commit `78e1ff5`). Future attempts to paste any variant of
|
||
the legacy password — in source, shell scripts, or env files — will
|
||
fail the `gitleaks` CI job wired in PR #5.
|
||
|
||
## Build-time / CI checks (wired in PR #5)
|
||
|
||
- `gitleaks` pre-commit + CI gate on every PR.
|
||
- `govulncheck`, `staticcheck`, and `go vet -vet=all` on the backend.
|
||
- `eslint` and `tsc --noEmit` on the frontend.
|
||
|
||
## Reporting a vulnerability
|
||
|
||
Do not open public issues for security reports. Email the maintainers
|
||
listed in `CONTRIBUTING.md`.
|