security(history): scrub admin:admin123 from .claude/skills/transcribe/SKILL.md git history #460

Open
opened 2026-05-07 17:22:18 +02:00 by marcel · 8 comments
Owner

Context

gitleaks detect --source . reports the credential admin:admin123 committed to git history at line 96 of .claude/skills/transcribe/SKILL.md, in commits 3d3d4b86 and fc27043d (both 2026-04-14):

RULE:    curl-auth-user
FILE:    .claude/skills/transcribe/SKILL.md  (line 96)
COMMIT:  3d3d4b86166b
SECRET:  admin:admin123
MATCH:   curl -s -u admin:admin123 ...

The same string appears in 6 worktrees under .worktrees/ and .claude/worktrees/ (working-tree only — those won't propagate when push-cleaned).

This is the same credential still hardcoded in application.yaml:67 (#83). Even after #83 lands, the value admin123 should be removed from the documentation history because:

  1. The repo is public (or could become public).
  2. Any developer who clones the repo today gets the secret in their reflog.
  3. CI test fixtures may have been generated against the same default; a forensic timeline matters if a leak is suspected.

Approach

Two-step:

1. Replace the literal in current docs

Change every occurrence of admin:admin123 in .claude/skills/transcribe/SKILL.md and any other tracked file to admin:$ADMIN_PASS with a one-line note:

# Set ADMIN_PASS to your local APP_ADMIN_PASSWORD (see .env or DEPLOYMENT.md)
curl -s -u "admin:$ADMIN_PASS" http://localhost:8080/api/...

Commit and push.

2. Scrub from history

Pick git filter-repo (preferred, faster, sanctioned) over bfg:

echo 'admin:admin123==>admin:$ADMIN_PASS' > expressions.txt
git filter-repo --replace-text expressions.txt

After force-push to main:

  • Notify any other clones (none expected — solo repo) that they need to git fetch --all && git reset --hard origin/main.
  • Re-tag the latest production release if any tags pointed to a rewritten commit.
  • The two original commits (3d3d4b86, fc27043d) become rewritten commits with new SHAs.

3. Rotate the credential anyway

Even after scrubbing, treat admin123 as compromised forever (it was public). Once #83 lands, set a strong APP_ADMIN_PASSWORD and rotate any account that ever used the default.

Critical files

  • .claude/skills/transcribe/SKILL.md (line 96 + any other occurrences)
  • expressions.txt (one-shot, not committed)

Verification

  1. gitleaks detect --source . after the scrub returns 0 secrets in history.
  2. gitleaks dir . working-tree scan returns 0 secrets (after worktrees are also cleaned).
  3. git log -p .claude/skills/transcribe/SKILL.md | grep -c admin:admin123 → 0.
  4. Manual review: latest commit on the file uses $ADMIN_PASS with a comment.

Acceptance criteria

  • No occurrence of admin:admin123 in any tracked file (working tree).
  • No occurrence of admin:admin123 in any commit reachable from main or any branch.
  • Worktrees under .worktrees/ either deleted or refreshed.
  • Solo-repo coordination: confirmed no live clones still have old refs.
  • Rotated production admin password (after #83 fix lands).

Effort

S — 1 hour for the scrub. The rotation depends on #83.

Risk if not addressed

The default password value is permanently public in git reflog. Any future deployment misconfiguration that re-enables the default (per #83) immediately exposes a known credential.

Tracked in audit doc as A.3 of docs/audits/2026-05-07-pre-prod-architectural-review.md.

## Context `gitleaks detect --source .` reports the credential `admin:admin123` committed to git history at line 96 of `.claude/skills/transcribe/SKILL.md`, in commits `3d3d4b86` and `fc27043d` (both 2026-04-14): ``` RULE: curl-auth-user FILE: .claude/skills/transcribe/SKILL.md (line 96) COMMIT: 3d3d4b86166b SECRET: admin:admin123 MATCH: curl -s -u admin:admin123 ... ``` The same string appears in 6 worktrees under `.worktrees/` and `.claude/worktrees/` (working-tree only — those won't propagate when push-cleaned). This is the **same credential** still hardcoded in `application.yaml:67` (#83). Even after #83 lands, the value `admin123` should be removed from the documentation history because: 1. The repo is public (or could become public). 2. Any developer who clones the repo today gets the secret in their reflog. 3. CI test fixtures may have been generated against the same default; a forensic timeline matters if a leak is suspected. ## Approach Two-step: ### 1. Replace the literal in current docs Change every occurrence of `admin:admin123` in `.claude/skills/transcribe/SKILL.md` and any other tracked file to `admin:$ADMIN_PASS` with a one-line note: ```bash # Set ADMIN_PASS to your local APP_ADMIN_PASSWORD (see .env or DEPLOYMENT.md) curl -s -u "admin:$ADMIN_PASS" http://localhost:8080/api/... ``` Commit and push. ### 2. Scrub from history Pick `git filter-repo` (preferred, faster, sanctioned) over `bfg`: ```bash echo 'admin:admin123==>admin:$ADMIN_PASS' > expressions.txt git filter-repo --replace-text expressions.txt ``` After force-push to `main`: - Notify any other clones (none expected — solo repo) that they need to `git fetch --all && git reset --hard origin/main`. - Re-tag the latest production release if any tags pointed to a rewritten commit. - The two original commits (`3d3d4b86`, `fc27043d`) become rewritten commits with new SHAs. ### 3. Rotate the credential anyway Even after scrubbing, treat `admin123` as compromised forever (it was public). Once #83 lands, set a strong `APP_ADMIN_PASSWORD` and rotate any account that ever used the default. ## Critical files - `.claude/skills/transcribe/SKILL.md` (line 96 + any other occurrences) - `expressions.txt` (one-shot, not committed) ## Verification 1. `gitleaks detect --source .` after the scrub returns 0 secrets in history. 2. `gitleaks dir .` working-tree scan returns 0 secrets (after worktrees are also cleaned). 3. `git log -p .claude/skills/transcribe/SKILL.md | grep -c admin:admin123` → 0. 4. Manual review: latest commit on the file uses `$ADMIN_PASS` with a comment. ## Acceptance criteria - [ ] No occurrence of `admin:admin123` in any tracked file (working tree). - [ ] No occurrence of `admin:admin123` in any commit reachable from `main` or any branch. - [ ] Worktrees under `.worktrees/` either deleted or refreshed. - [ ] Solo-repo coordination: confirmed no live clones still have old refs. - [ ] Rotated production admin password (after #83 fix lands). ## Effort S — 1 hour for the scrub. The rotation depends on #83. ## Risk if not addressed The default password value is permanently public in git reflog. Any future deployment misconfiguration that re-enables the default (per #83) immediately exposes a known credential. Tracked in audit doc as **A.3** of `docs/audits/2026-05-07-pre-prod-architectural-review.md`.
marcel added the P1-highsecurity labels 2026-05-07 17:23:33 +02:00
Author
Owner

🔐 Nora "NullX" Steiner — Application Security Engineer

Observations

  • Two distinct problems, one issue. The issue correctly bundles them, but the fix sequence matters: (1) scrub history, (2) remove the working-tree literal, (3) rotate the credential, (4) fix #83 so admin123 can never be a runtime default again. Doing them out of order is harmless but creates confusion about what is "done".

  • Working-tree exposure is wider than the issue states. admin:admin123 appears in two lines of .claude/skills/transcribe/SKILL.md (lines 23 and 98). The issue mentions line 96 — that is slightly off, but both occurrences are in the same file and will be caught by the same filter-repo run.

  • README.md:60 also ships admin123 in plaintext (Password: admin123). This is in the working tree of the tracked file README.md, reachable from main. It is not mentioned in the issue but will be found by gitleaks detect and must be addressed in the same pass.

  • .claude/settings.local.json contains E2E_PASSWORD=admin123 in 8 allowList entries. Whether this file is tracked determines the history scope. It is present on disk but should be verified against .gitignore before the scrub — if tracked, it is another history hit.

  • UserDataInitializer.java:37 uses @Value("${app.admin.password:admin123}") — this is a Spring property default that will activate if APP_ADMIN_PASSWORD is not set. This is the root cause tracked as #83. It is explicitly out of scope for this issue but worth noting: until #83 is closed, admin123 remains a valid runtime password even after the history scrub.

  • docs/TODO-backend.md contains admin123 in code snippets — another tracked file with the literal. The filter-repo replace-text approach will catch it automatically.

  • The gitleaks scan identified commits 3d3d4b86 and fc27043d — both are the same "add personas/skills" commit appearing to exist on two branches (likely main and an old feature branch). After filter-repo --replace-text, both will receive new SHAs. Any local clones and the remote origin at ssh://git@heim-nas:222/ must be force-pushed to.

  • CWE-798 (Use of Hard-coded Credentials in Documentation) — low individual severity, high aggregate risk: if this repo is ever made public, or if a deploy script copies the value literally, the credential is permanently compromised.

Recommendations

  1. Replace both working-tree occurrences first, commit, then scrub history — this keeps the working tree clean independently of the history rewrite, which can be done separately without time pressure.

  2. Expand the expressions.txt to cover all literal occurrences before running filter-repo:

    admin:admin123==>admin:$ADMIN_PASS
    password: admin123==>password: $ADMIN_PASS
    admin123==>$ADMIN_PASS
    

    Be deliberate — a blanket replacement of admin123 everywhere may hit persona .md files where the string appears as a counter-example (e.g., security_expert.md:147). Scope the replacement to the specific files: .claude/skills/transcribe/SKILL.md, README.md, docs/TODO-backend.md.

  3. Verify settings.local.json is in .gitignore before running the scrub. grep "settings.local" .gitignore — if it is not excluded, add it and include the file in the filter-repo run.

  4. After force-push, rotate the credential immediately — treat admin123 as permanently public regardless of the scrub success. Generate a strong password (≥20 chars, openssl rand -base64 20), update .env, and redeploy.

  5. Add gitleaks detect to the CI pipeline as a blocking step so no future commit can introduce credentials. The Gitea Actions ci.yml is the right place — add it as the first step before the build.

  6. Add APP_ADMIN_PASSWORD to .env.example with a change-me placeholder so it is obvious to any new developer that this must be set. Currently it is absent from .env.example.

Open Decisions

  • Scope of the filter-repo replacement: replacing the string everywhere in history (--replace-text) will rewrite every commit that contains admin123 — including persona files where it appears as a deliberate bad-example. Narrowing the scope with --path to only the affected files is cleaner but requires a separate pass per file. Recommend the narrow approach to avoid rewriting commits that are intentionally instructional.
  • README.md treatment: the README publicly documents admin123 as the dev default. After #83 lands and the default is removed, the README must be updated to reflect the new APP_ADMIN_PASSWORD pattern. This may belong in #83's scope rather than here.
## 🔐 Nora "NullX" Steiner — Application Security Engineer ### Observations - **Two distinct problems, one issue.** The issue correctly bundles them, but the fix sequence matters: (1) scrub history, (2) remove the working-tree literal, (3) rotate the credential, (4) fix #83 so `admin123` can never be a runtime default again. Doing them out of order is harmless but creates confusion about what is "done". - **Working-tree exposure is wider than the issue states.** `admin:admin123` appears in two lines of `.claude/skills/transcribe/SKILL.md` (lines 23 and 98). The issue mentions line 96 — that is slightly off, but both occurrences are in the same file and will be caught by the same `filter-repo` run. - **`README.md:60` also ships `admin123` in plaintext** (`Password: admin123`). This is in the working tree of the tracked file `README.md`, reachable from `main`. It is not mentioned in the issue but will be found by `gitleaks detect` and must be addressed in the same pass. - **`.claude/settings.local.json` contains `E2E_PASSWORD=admin123` in 8 `allowList` entries.** Whether this file is tracked determines the history scope. It is present on disk but should be verified against `.gitignore` before the scrub — if tracked, it is another history hit. - **`UserDataInitializer.java:37`** uses `@Value("${app.admin.password:admin123}")` — this is a Spring property default that will activate if `APP_ADMIN_PASSWORD` is not set. This is the root cause tracked as #83. It is explicitly out of scope for this issue but worth noting: until #83 is closed, `admin123` remains a valid runtime password even after the history scrub. - **`docs/TODO-backend.md`** contains `admin123` in code snippets — another tracked file with the literal. The `filter-repo` replace-text approach will catch it automatically. - **The `gitleaks` scan identified commits `3d3d4b86` and `fc27043d`** — both are the same "add personas/skills" commit appearing to exist on two branches (likely main and an old feature branch). After `filter-repo --replace-text`, both will receive new SHAs. Any local clones and the remote `origin` at `ssh://git@heim-nas:222/` must be force-pushed to. - **CWE-798** (Use of Hard-coded Credentials in Documentation) — low individual severity, high aggregate risk: if this repo is ever made public, or if a deploy script copies the value literally, the credential is permanently compromised. ### Recommendations 1. **Replace both working-tree occurrences first, commit, then scrub history** — this keeps the working tree clean independently of the history rewrite, which can be done separately without time pressure. 2. **Expand the `expressions.txt` to cover all literal occurrences** before running `filter-repo`: ``` admin:admin123==>admin:$ADMIN_PASS password: admin123==>password: $ADMIN_PASS admin123==>$ADMIN_PASS ``` Be deliberate — a blanket replacement of `admin123` everywhere may hit persona `.md` files where the string appears as a *counter-example* (e.g., `security_expert.md:147`). Scope the replacement to the specific files: `.claude/skills/transcribe/SKILL.md`, `README.md`, `docs/TODO-backend.md`. 3. **Verify `settings.local.json` is in `.gitignore`** before running the scrub. `grep "settings.local" .gitignore` — if it is not excluded, add it and include the file in the `filter-repo` run. 4. **After force-push, rotate the credential immediately** — treat `admin123` as permanently public regardless of the scrub success. Generate a strong password (≥20 chars, `openssl rand -base64 20`), update `.env`, and redeploy. 5. **Add `gitleaks detect` to the CI pipeline** as a blocking step so no future commit can introduce credentials. The Gitea Actions `ci.yml` is the right place — add it as the first step before the build. 6. **Add `APP_ADMIN_PASSWORD` to `.env.example`** with a `change-me` placeholder so it is obvious to any new developer that this must be set. Currently it is absent from `.env.example`. ### Open Decisions - **Scope of the `filter-repo` replacement**: replacing the string everywhere in history (`--replace-text`) will rewrite every commit that contains `admin123` — including persona files where it appears as a deliberate bad-example. Narrowing the scope with `--path` to only the affected files is cleaner but requires a separate pass per file. Recommend the narrow approach to avoid rewriting commits that are intentionally instructional. - **README.md treatment**: the README publicly documents `admin123` as the dev default. After #83 lands and the default is removed, the README must be updated to reflect the new `APP_ADMIN_PASSWORD` pattern. This may belong in #83's scope rather than here.
Author
Owner

🏗️ Markus Keller — Application Architect

Observations

  • This is a documentation hygiene problem, not an architecture problem — the credential leaked through a .claude/ skill file that documents a curl example, not through application configuration. The architectural problem (hardcoded Spring property default) is tracked separately as #83 and is correctly out of scope here.

  • The two commits that introduced the leak (3d3d4b86, fc27043d) exist on what appears to be main and at least one other branch. git filter-repo rewrites the entire reachable history, so both are handled in one pass. The issue's approach is correct.

  • filter-repo is the right toolbfg is easier for beginners but deprecated in practice; filter-repo is the current Git project recommendation and handles branch/tag rewriting atomically.

  • The application.yaml Spring property default (${APP_ADMIN_PASSWORD:admin123}) is an architectural smell: the application can start in production with a known credential if the env var is absent. Spring's fail-fast alternative is ${APP_ADMIN_PASSWORD:?APP_ADMIN_PASSWORD must be set} — this causes startup failure rather than silent insecure default. The audit doc already identifies this fix; it belongs in #83, not here.

  • No ADR is needed for this issue — it is a remediation task, not an architectural decision. The process for scrubbing credentials from history is a one-time operational action.

  • Documentation impact: the issue does not mention that README.md also contains admin123 as a publicly visible dev credential. That file is committed and on main. It should be covered in the same working-tree pass.

Recommendations

  1. Run the filter-repo scrub as a single coordinated operation — do not split it across multiple PRs or force-pushes. One atomic rewrite, one coordinated force-push to origin, one notification that all local clones (if any) must hard-reset. For a solo repo this is low coordination overhead.

  2. Scope the expressions.txt narrowly to the affected documentation files rather than a global string replace. A global admin123 ==> $ADMIN_PASS rewrite will touch security_expert.md and devops.md where the string appears as a deliberate negative example, changing the meaning of the documentation.

  3. Do not delete the skill file — the curl examples in .claude/skills/transcribe/SKILL.md are functionally necessary. Replace the literal credential with $ADMIN_PASS and add a one-line comment pointing to .env or DEPLOYMENT.md. The skill stays useful.

  4. After the scrub, add APP_ADMIN_PASSWORD to .env.example with a change-me value and a comment. Currently that file documents PostgreSQL, MinIO, and OCR tokens but omits the admin password entirely — which is why it gets forgotten.

  5. Treat the history rewrite as a one-way door — once filter-repo rewrites and the force-push lands, all old SHAs are gone. Verify the gitleaks detect clean output before the push. Roll back is not possible after the remote is updated without a backup of the original reflog (which filter-repo provides in refs/filter-repo/).

  6. Tag the post-scrub HEAD as a known-clean baseline — e.g., git tag security/history-scrub-460 after the force-push. This gives future forensic investigation a named point that is known to be clean.

## 🏗️ Markus Keller — Application Architect ### Observations - **This is a documentation hygiene problem, not an architecture problem** — the credential leaked through a `.claude/` skill file that documents a `curl` example, not through application configuration. The architectural problem (hardcoded Spring property default) is tracked separately as #83 and is correctly out of scope here. - **The two commits that introduced the leak (`3d3d4b86`, `fc27043d`) exist on what appears to be main and at least one other branch.** `git filter-repo` rewrites the entire reachable history, so both are handled in one pass. The issue's approach is correct. - **`filter-repo` is the right tool** — `bfg` is easier for beginners but deprecated in practice; `filter-repo` is the current Git project recommendation and handles branch/tag rewriting atomically. - **The `application.yaml` Spring property default** (`${APP_ADMIN_PASSWORD:admin123}`) is an architectural smell: the application can start in production with a known credential if the env var is absent. Spring's fail-fast alternative is `${APP_ADMIN_PASSWORD:?APP_ADMIN_PASSWORD must be set}` — this causes startup failure rather than silent insecure default. The audit doc already identifies this fix; it belongs in #83, not here. - **No ADR is needed** for this issue — it is a remediation task, not an architectural decision. The process for scrubbing credentials from history is a one-time operational action. - **Documentation impact**: the issue does not mention that `README.md` also contains `admin123` as a publicly visible dev credential. That file is committed and on main. It should be covered in the same working-tree pass. ### Recommendations 1. **Run the `filter-repo` scrub as a single coordinated operation** — do not split it across multiple PRs or force-pushes. One atomic rewrite, one coordinated force-push to `origin`, one notification that all local clones (if any) must hard-reset. For a solo repo this is low coordination overhead. 2. **Scope the `expressions.txt` narrowly** to the affected documentation files rather than a global string replace. A global `admin123 ==> $ADMIN_PASS` rewrite will touch `security_expert.md` and `devops.md` where the string appears as a *deliberate negative example*, changing the meaning of the documentation. 3. **Do not delete the skill file** — the `curl` examples in `.claude/skills/transcribe/SKILL.md` are functionally necessary. Replace the literal credential with `$ADMIN_PASS` and add a one-line comment pointing to `.env` or `DEPLOYMENT.md`. The skill stays useful. 4. **After the scrub, add `APP_ADMIN_PASSWORD` to `.env.example`** with a `change-me` value and a comment. Currently that file documents PostgreSQL, MinIO, and OCR tokens but omits the admin password entirely — which is why it gets forgotten. 5. **Treat the history rewrite as a one-way door** — once `filter-repo` rewrites and the force-push lands, all old SHAs are gone. Verify the `gitleaks detect` clean output before the push. Roll back is not possible after the remote is updated without a backup of the original reflog (which `filter-repo` provides in `refs/filter-repo/`). 6. **Tag the post-scrub HEAD as a known-clean baseline** — e.g., `git tag security/history-scrub-460` after the force-push. This gives future forensic investigation a named point that is known to be clean.
Author
Owner

⚙️ Tobias Wendt — DevOps & Platform Engineer

Observations

  • The credential is in the git history on the origin remote (ssh://git@heim-nas:222/marcel/familienarchiv.git). The working-tree fix alone does nothing for the history — the remote must receive a force-push after filter-repo rewrites local history.

  • settings.local.json has E2E_PASSWORD=admin123 in 8 Bash allowList entries. If this file is tracked (it is present on disk; .gitignore has .env excluded but not necessarily settings.local.json explicitly), it is another history hit. Run git ls-files .claude/settings.local.json to confirm tracking status. If tracked, include it in the scrub.

  • The CI workflow .gitea/workflows/ci.yml does not hardcode the credential — looking at the infrastructure docs (docs/infrastructure/ci-gitea.md), the CI correctly passes ${{ secrets.E2E_ADMIN_PASSWORD }} via Gitea secrets. This is the right pattern and is not affected by this issue.

  • APP_ADMIN_PASSWORD is absent from .env.example — the example env file documents PostgreSQL, MinIO, Mailpit, and OCR tokens, but not the admin password. This is a gap: anyone standing up the app from scratch will get admin123 by default without realizing it. Adding APP_ADMIN_PASSWORD=change-me to .env.example closes this gap.

  • Docker Compose does not pass APP_ADMIN_PASSWORD to the backend container in the current docker-compose.yml (nothing visible in the grep). If the env var is not wired through Compose, the Spring fallback admin123 will always be used in local dev — exactly the wrong default.

  • No self-hosted Renovate or secret-scanning CI step is currently visible. After the scrub, a gitleaks detect CI step should be the first gate in ci.yml to prevent future leaks.

Recommendations

  1. Before the filter-repo run, confirm tracking status of all candidate files:

    git ls-files .claude/settings.local.json .claude/skills/transcribe/SKILL.md README.md docs/TODO-backend.md
    

    Only rewrite what is actually tracked — untracked files in working tree do not propagate.

  2. Add APP_ADMIN_PASSWORD=change-me to .env.example immediately (can be done as a normal commit before the history rewrite — it does not add a secret, it adds a placeholder). Also wire it through docker-compose.yml under the backend service's environment: block using APP_ADMIN_PASSWORD: ${APP_ADMIN_PASSWORD}.

  3. Back up the remote's reflog before force-pushing:

    git fetch origin
    git branch backup/pre-scrub-main origin/main
    

    filter-repo automatically saves the original refs to refs/filter-repo/ locally, but having a named branch on the remote as a safety net costs nothing and enables recovery if the push goes wrong.

  4. Add gitleaks detect --source . --exit-code 1 as the first step in .gitea/workflows/ci.yml using the gitleaks/gitleaks Docker image. This turns the scan into a mandatory gate on every PR and push, preventing the same class of problem from recurring.

  5. After the scrub and force-push, verify the remote is clean:

    git clone ssh://git@heim-nas:222/marcel/familienarchiv.git /tmp/verify-clone
    gitleaks detect --source /tmp/verify-clone --exit-code 1
    

    Cloning fresh from the remote is the definitive test — it proves the rewritten history propagated correctly.

  6. Update the worktrees under .worktrees/ — the issue notes these contain working-tree occurrences. Either delete and recreate them from the cleaned remote, or run the replace in them manually. They do not affect the remote history but will confuse local gitleaks scans.

## ⚙️ Tobias Wendt — DevOps & Platform Engineer ### Observations - **The credential is in the git history on the `origin` remote** (`ssh://git@heim-nas:222/marcel/familienarchiv.git`). The working-tree fix alone does nothing for the history — the remote must receive a force-push after `filter-repo` rewrites local history. - **`settings.local.json` has `E2E_PASSWORD=admin123` in 8 Bash `allowList` entries.** If this file is tracked (it is present on disk; `.gitignore` has `.env` excluded but not necessarily `settings.local.json` explicitly), it is another history hit. Run `git ls-files .claude/settings.local.json` to confirm tracking status. If tracked, include it in the scrub. - **The CI workflow `.gitea/workflows/ci.yml` does not hardcode the credential** — looking at the infrastructure docs (`docs/infrastructure/ci-gitea.md`), the CI correctly passes `${{ secrets.E2E_ADMIN_PASSWORD }}` via Gitea secrets. This is the right pattern and is not affected by this issue. - **`APP_ADMIN_PASSWORD` is absent from `.env.example`** — the example env file documents PostgreSQL, MinIO, Mailpit, and OCR tokens, but not the admin password. This is a gap: anyone standing up the app from scratch will get `admin123` by default without realizing it. Adding `APP_ADMIN_PASSWORD=change-me` to `.env.example` closes this gap. - **Docker Compose** does not pass `APP_ADMIN_PASSWORD` to the backend container in the current `docker-compose.yml` (nothing visible in the grep). If the env var is not wired through Compose, the Spring fallback `admin123` will always be used in local dev — exactly the wrong default. - **No self-hosted Renovate or secret-scanning CI step** is currently visible. After the scrub, a `gitleaks detect` CI step should be the first gate in `ci.yml` to prevent future leaks. ### Recommendations 1. **Before the `filter-repo` run, confirm tracking status of all candidate files:** ```bash git ls-files .claude/settings.local.json .claude/skills/transcribe/SKILL.md README.md docs/TODO-backend.md ``` Only rewrite what is actually tracked — untracked files in working tree do not propagate. 2. **Add `APP_ADMIN_PASSWORD=change-me` to `.env.example`** immediately (can be done as a normal commit before the history rewrite — it does not add a secret, it adds a placeholder). Also wire it through `docker-compose.yml` under the backend service's `environment:` block using `APP_ADMIN_PASSWORD: ${APP_ADMIN_PASSWORD}`. 3. **Back up the remote's reflog before force-pushing:** ```bash git fetch origin git branch backup/pre-scrub-main origin/main ``` `filter-repo` automatically saves the original refs to `refs/filter-repo/` locally, but having a named branch on the remote as a safety net costs nothing and enables recovery if the push goes wrong. 4. **Add `gitleaks detect --source . --exit-code 1` as the first step in `.gitea/workflows/ci.yml`** using the `gitleaks/gitleaks` Docker image. This turns the scan into a mandatory gate on every PR and push, preventing the same class of problem from recurring. 5. **After the scrub and force-push, verify the remote is clean:** ```bash git clone ssh://git@heim-nas:222/marcel/familienarchiv.git /tmp/verify-clone gitleaks detect --source /tmp/verify-clone --exit-code 1 ``` Cloning fresh from the remote is the definitive test — it proves the rewritten history propagated correctly. 6. **Update the worktrees under `.worktrees/`** — the issue notes these contain working-tree occurrences. Either delete and recreate them from the cleaned remote, or run the replace in them manually. They do not affect the remote history but will confuse local `gitleaks` scans.
Author
Owner

🧪 Felix Brandt — Senior Fullstack Developer

Observations

  • The literal replacement in SKILL.md is a documentation change, not a code change — no tests required for that part. The credential in SKILL.md lines 23 and 98 is in a curl example that Claude reads at runtime; replacing it with $ADMIN_PASS + a comment is safe and does not change any application behavior.

  • UserDataInitializer.java:37 (@Value("${app.admin.password:admin123}")) is the application-code side of this problem and belongs to #83. Worth noting that this class also has reader123 hardcoded at line 99 for the E2E reader user — a similar smell that should be addressed when #83 is tackled. The E2E user passwords should come from an env var or a test-specific profile override, not from literals in the initializer.

  • The README.md has Password: admin123 at line 60 — this is a tracked, publicly visible file. The fix here is to replace it with something like Password: [set via APP_ADMIN_PASSWORD] with a pointer to DEPLOYMENT.md. This is a one-line edit and should be in the same working-tree cleanup commit.

  • docs/TODO-backend.md contains code snippets with admin123. These look like historical notes, not active code. They are tracked and will appear in gitleaks output.

  • No E2E tests reference admin123 directly in the test files I can check — the CI workflow docs show ${{ secrets.E2E_ADMIN_PASSWORD }} is used. The settings.local.json allowlist entries with E2E_PASSWORD=admin123 are for local dev convenience; if the file is untracked these have no git history impact.

Recommendations

  1. Make the working-tree fix a clean, atomic commit before the history rewrite:

    • .claude/skills/transcribe/SKILL.md lines 23 and 98: replace admin:admin123 with admin:$ADMIN_PASS + add comment on line above:
      # Set ADMIN_PASS to your APP_ADMIN_PASSWORD value (see .env or DEPLOYMENT.md)
      curl -s -u "admin:$ADMIN_PASS" ...
      
    • README.md: replace Password: admin123 with Password: [see APP_ADMIN_PASSWORD in .env]
    • docs/TODO-backend.md: replace admin123 occurrences with $ADMIN_PASS
    • Do this in a single commit with message security(docs): replace admin:admin123 literals with $ADMIN_PASS placeholder
  2. After the history rewrite, the working-tree commit will be rewritten too — this is fine. The important thing is that the commit exists on the clean HEAD before the force-push so the current state of files is correct.

  3. reader123 in UserDataInitializer.java:99 should be added to #83's scope — it is the same class of problem (hardcoded credential in tracked source) and should be fixed at the same time as the admin password default removal.

  4. Verify no E2E test file hardcodes the password — run grep -rn "admin123" frontend/e2e/ before closing this issue. From what I can see the tests use process.env.E2E_PASSWORD, which is correct.

  5. docs/TODO-backend.md appears to be a development scratchpad — check whether it should remain tracked at all, or whether it belongs in .gitignore. If it is kept tracked, clean it up.

## 🧪 Felix Brandt — Senior Fullstack Developer ### Observations - **The literal replacement in `SKILL.md` is a documentation change, not a code change** — no tests required for that part. The credential in `SKILL.md` lines 23 and 98 is in a `curl` example that Claude reads at runtime; replacing it with `$ADMIN_PASS` + a comment is safe and does not change any application behavior. - **`UserDataInitializer.java:37`** (`@Value("${app.admin.password:admin123}")`) is the application-code side of this problem and belongs to #83. Worth noting that this class also has `reader123` hardcoded at line 99 for the E2E reader user — a similar smell that should be addressed when #83 is tackled. The E2E user passwords should come from an env var or a test-specific profile override, not from literals in the initializer. - **The `README.md` has `Password: admin123` at line 60** — this is a tracked, publicly visible file. The fix here is to replace it with something like `Password: [set via APP_ADMIN_PASSWORD]` with a pointer to `DEPLOYMENT.md`. This is a one-line edit and should be in the same working-tree cleanup commit. - **`docs/TODO-backend.md`** contains code snippets with `admin123`. These look like historical notes, not active code. They are tracked and will appear in `gitleaks` output. - **No E2E tests reference `admin123` directly** in the test files I can check — the CI workflow docs show `${{ secrets.E2E_ADMIN_PASSWORD }}` is used. The `settings.local.json` allowlist entries with `E2E_PASSWORD=admin123` are for local dev convenience; if the file is untracked these have no git history impact. ### Recommendations 1. **Make the working-tree fix a clean, atomic commit before the history rewrite:** - `.claude/skills/transcribe/SKILL.md` lines 23 and 98: replace `admin:admin123` with `admin:$ADMIN_PASS` + add comment on line above: ```bash # Set ADMIN_PASS to your APP_ADMIN_PASSWORD value (see .env or DEPLOYMENT.md) curl -s -u "admin:$ADMIN_PASS" ... ``` - `README.md`: replace `Password: admin123` with `Password: [see APP_ADMIN_PASSWORD in .env]` - `docs/TODO-backend.md`: replace `admin123` occurrences with `$ADMIN_PASS` - Do this in a single commit with message `security(docs): replace admin:admin123 literals with $ADMIN_PASS placeholder` 2. **After the history rewrite, the working-tree commit will be rewritten too** — this is fine. The important thing is that the commit exists on the clean HEAD before the force-push so the current state of files is correct. 3. **`reader123` in `UserDataInitializer.java:99`** should be added to #83's scope — it is the same class of problem (hardcoded credential in tracked source) and should be fixed at the same time as the admin password default removal. 4. **Verify no E2E test file hardcodes the password** — run `grep -rn "admin123" frontend/e2e/` before closing this issue. From what I can see the tests use `process.env.E2E_PASSWORD`, which is correct. 5. **`docs/TODO-backend.md`** appears to be a development scratchpad — check whether it should remain tracked at all, or whether it belongs in `.gitignore`. If it is kept tracked, clean it up.
Author
Owner

📋 Elicit — Requirements Engineer

Observations

  • The issue is well-specified for a remediation task. It has a clear context, a two-step approach, verification steps, and acceptance criteria. The effort estimate (S, 1 hour for the scrub) is realistic for the filter-repo step alone. The rotation step depends on #83, which is correctly flagged as a dependency.

  • Scope gap: additional tracked files. The issue specifies .claude/skills/transcribe/SKILL.md and expressions.txt (one-shot) as the only affected files. In fact, README.md and docs/TODO-backend.md also contain admin123 as tracked files. The acceptance criteria — "No occurrence of admin:admin123 in any tracked file" — will fail unless these are included in the working-tree fix. The issue should explicitly list all files to be modified.

  • Acceptance criterion ambiguity: "any commit reachable from main or any branch." The repo has 30+ branches (visible from git branch -a). The filter-repo run rewrites all branches by default, so this criterion is met automatically — but it should be confirmed explicitly. The verification step should be: git log --all -p | grep -c "admin:admin123" → 0, not just checking main.

  • Missing acceptance criterion: the remote. The working tree and local git history can be clean while the remote (origin) still has the old commits. The acceptance criteria should include: "Remote origin has been force-pushed and a fresh clone produces 0 gitleaks findings."

  • Dependency on #83 is correctly modeled — the rotation step is explicitly blocked by #83. However, APP_ADMIN_PASSWORD being absent from .env.example is a separate gap that does not depend on #83 and could be closed immediately. This should be an acceptance criterion here, or a sub-task.

  • The effort estimate excludes credential rotation. If #83 is worked in parallel, the total effort is more than 1 hour. This is acknowledged in the issue ("The rotation depends on #83"), but the estimate should note that the full remediation (scrub + rotation) is an M not an S.

Recommendations

  1. Add a pre-work checklist to the issue (or this comment serves as a supplement):

    • List all tracked files containing admin123: SKILL.md, README.md, docs/TODO-backend.md, docs/DEPLOYMENT.md (informational references, not literal credentials — verify each)
    • Confirm tracking status: git ls-files <file> for each
    • Confirm no E2E test files hardcode the password: grep -rn "admin123" frontend/e2e/
  2. Add "remote origin updated" as an explicit acceptance criterion — the scrub is not done until the remote is clean and a fresh clone confirms it.

  3. Add "APP_ADMIN_PASSWORD added to .env.example" as an acceptance criterion — this is independent of #83 and closes a real gap in the onboarding documentation.

  4. Clarify the scope of expressions.txt in the issue — document exactly which string patterns will be replaced to avoid accidentally rewriting persona .md files where admin123 appears as a counter-example.

  5. The issue title says "scrub from git history" — this is correct, but the body conflates the history scrub with the working-tree literal replacement. Separating these into two numbered items (as the issue does) is the right structure; just ensure the acceptance criteria reflect both tracks independently.

## 📋 Elicit — Requirements Engineer ### Observations - **The issue is well-specified for a remediation task.** It has a clear context, a two-step approach, verification steps, and acceptance criteria. The effort estimate (S, 1 hour for the scrub) is realistic for the `filter-repo` step alone. The rotation step depends on #83, which is correctly flagged as a dependency. - **Scope gap: additional tracked files.** The issue specifies `.claude/skills/transcribe/SKILL.md` and `expressions.txt` (one-shot) as the only affected files. In fact, `README.md` and `docs/TODO-backend.md` also contain `admin123` as tracked files. The acceptance criteria — "No occurrence of `admin:admin123` in any tracked file" — will fail unless these are included in the working-tree fix. The issue should explicitly list all files to be modified. - **Acceptance criterion ambiguity: "any commit reachable from main or any branch."** The repo has 30+ branches (visible from `git branch -a`). The `filter-repo` run rewrites all branches by default, so this criterion is met automatically — but it should be confirmed explicitly. The verification step should be: `git log --all -p | grep -c "admin:admin123"` → 0, not just checking `main`. - **Missing acceptance criterion: the remote.** The working tree and local git history can be clean while the remote (`origin`) still has the old commits. The acceptance criteria should include: "Remote `origin` has been force-pushed and a fresh clone produces 0 `gitleaks` findings." - **Dependency on #83 is correctly modeled** — the rotation step is explicitly blocked by #83. However, `APP_ADMIN_PASSWORD` being absent from `.env.example` is a separate gap that does not depend on #83 and could be closed immediately. This should be an acceptance criterion here, or a sub-task. - **The effort estimate excludes credential rotation.** If #83 is worked in parallel, the total effort is more than 1 hour. This is acknowledged in the issue ("The rotation depends on #83"), but the estimate should note that the full remediation (scrub + rotation) is an M not an S. ### Recommendations 1. **Add a pre-work checklist to the issue** (or this comment serves as a supplement): - List all tracked files containing `admin123`: `SKILL.md`, `README.md`, `docs/TODO-backend.md`, `docs/DEPLOYMENT.md` (informational references, not literal credentials — verify each) - Confirm tracking status: `git ls-files <file>` for each - Confirm no E2E test files hardcode the password: `grep -rn "admin123" frontend/e2e/` 2. **Add "remote origin updated" as an explicit acceptance criterion** — the scrub is not done until the remote is clean and a fresh clone confirms it. 3. **Add "APP_ADMIN_PASSWORD added to `.env.example`"** as an acceptance criterion — this is independent of #83 and closes a real gap in the onboarding documentation. 4. **Clarify the scope of `expressions.txt`** in the issue — document exactly which string patterns will be replaced to avoid accidentally rewriting persona `.md` files where `admin123` appears as a counter-example. 5. **The issue title says "scrub from git history"** — this is correct, but the body conflates the history scrub with the working-tree literal replacement. Separating these into two numbered items (as the issue does) is the right structure; just ensure the acceptance criteria reflect both tracks independently.
Author
Owner

🧪 Sara Holt — QA Engineer & Test Strategist

Observations

  • No test coverage is needed for the filter-repo history rewrite itself — it is an operational action, not a code change. But the verification of the scrub is a testable activity, and the issue's verification steps are a good informal test plan.

  • The issue's verification step 3 (git log -p .claude/skills/transcribe/SKILL.md | grep -c admin:admin123 → 0) checks only one file. A more thorough check covers all tracked files: git log --all -p | grep "admin:admin123" | wc -l. This should be ≥0 before the scrub and exactly 0 after.

  • gitleaks detect --source . vs gitleaks detect --no-git — the issue uses gitleaks detect --source . (history scan) and gitleaks dir . (working tree). The correct working-tree command is gitleaks detect --no-git (or gitleaks detect --source . --no-git). gitleaks dir was the old CLI; current gitleaks v8+ uses detect --no-git. Verify the installed version to use the correct flags.

  • The worktrees under .worktrees/ and .claude/worktrees/ contain working-tree occurrences. These are not in git history (as the issue correctly notes), but if a worktree-aware gitleaks scan runs, it may flag them. The acceptance criterion "Worktrees either deleted or refreshed" is correct — deletion is easier and safer.

  • Regression prevention: the issue does not specify a permanent gate to prevent recurrence. Once the scrub is done, nothing stops the next curl example from hardcoding admin123 again. A gitleaks pre-commit hook or CI gate closes this.

  • The E2E suite currently passes E2E_PASSWORD via environment variable — this is the correct pattern. There is no test regression risk from this issue.

Recommendations

  1. Use a comprehensive post-scrub verification script rather than individual commands:

    #!/bin/bash
    set -e
    echo "=== History scan ==="
    git log --all -p | grep "admin:admin123" | wc -l  # must be 0
    
    echo "=== Working tree scan ==="
    gitleaks detect --no-git --source . --exit-code 1
    
    echo "=== Clone verify (from remote) ==="
    git clone ssh://git@heim-nas:222/marcel/familienarchiv.git /tmp/scrub-verify
    gitleaks detect --source /tmp/scrub-verify --exit-code 1
    rm -rf /tmp/scrub-verify
    echo "PASSED"
    
  2. Add a gitleaks pre-commit hook post-scrub using pre-commit framework or a simple .git/hooks/pre-commit script. This is the cheapest permanent gate.

  3. Add gitleaks detect --exit-code 1 as step 1 of .gitea/workflows/ci.yml — before any build steps. A credential in a PR should fail CI immediately, not at the end of a 10-minute pipeline.

  4. For the .env.example addition: verify that APP_ADMIN_PASSWORD=change-me is added and that a CI test step (or linting rule) catches when .env.example is missing a key that application.yaml expects. This is lightweight "documentation test" but prevents the same gap from recurring.

  5. Delete the worktrees rather than refreshing them — refreshing a worktree after a history rewrite requires git worktree remove && git worktree add, which is equivalent to deletion and recreation. Deletion is simpler and leaves no stale refs.

## 🧪 Sara Holt — QA Engineer & Test Strategist ### Observations - **No test coverage is needed for the `filter-repo` history rewrite itself** — it is an operational action, not a code change. But the *verification* of the scrub is a testable activity, and the issue's verification steps are a good informal test plan. - **The issue's verification step 3** (`git log -p .claude/skills/transcribe/SKILL.md | grep -c admin:admin123 → 0`) checks only one file. A more thorough check covers all tracked files: `git log --all -p | grep "admin:admin123" | wc -l`. This should be ≥0 before the scrub and exactly 0 after. - **`gitleaks detect --source .` vs `gitleaks detect --no-git`** — the issue uses `gitleaks detect --source .` (history scan) and `gitleaks dir .` (working tree). The correct working-tree command is `gitleaks detect --no-git` (or `gitleaks detect --source . --no-git`). `gitleaks dir` was the old CLI; current `gitleaks` v8+ uses `detect --no-git`. Verify the installed version to use the correct flags. - **The worktrees under `.worktrees/` and `.claude/worktrees/`** contain working-tree occurrences. These are not in git history (as the issue correctly notes), but if a worktree-aware `gitleaks` scan runs, it may flag them. The acceptance criterion "Worktrees either deleted or refreshed" is correct — deletion is easier and safer. - **Regression prevention**: the issue does not specify a permanent gate to prevent recurrence. Once the scrub is done, nothing stops the next `curl` example from hardcoding `admin123` again. A `gitleaks` pre-commit hook or CI gate closes this. - **The E2E suite currently passes `E2E_PASSWORD` via environment variable** — this is the correct pattern. There is no test regression risk from this issue. ### Recommendations 1. **Use a comprehensive post-scrub verification script** rather than individual commands: ```bash #!/bin/bash set -e echo "=== History scan ===" git log --all -p | grep "admin:admin123" | wc -l # must be 0 echo "=== Working tree scan ===" gitleaks detect --no-git --source . --exit-code 1 echo "=== Clone verify (from remote) ===" git clone ssh://git@heim-nas:222/marcel/familienarchiv.git /tmp/scrub-verify gitleaks detect --source /tmp/scrub-verify --exit-code 1 rm -rf /tmp/scrub-verify echo "PASSED" ``` 2. **Add a `gitleaks` pre-commit hook** post-scrub using `pre-commit` framework or a simple `.git/hooks/pre-commit` script. This is the cheapest permanent gate. 3. **Add `gitleaks detect --exit-code 1` as step 1 of `.gitea/workflows/ci.yml`** — before any build steps. A credential in a PR should fail CI immediately, not at the end of a 10-minute pipeline. 4. **For the `.env.example` addition**: verify that `APP_ADMIN_PASSWORD=change-me` is added and that a CI test step (or linting rule) catches when `.env.example` is missing a key that `application.yaml` expects. This is lightweight "documentation test" but prevents the same gap from recurring. 5. **Delete the worktrees rather than refreshing them** — refreshing a worktree after a history rewrite requires `git worktree remove && git worktree add`, which is equivalent to deletion and recreation. Deletion is simpler and leaves no stale refs.
Author
Owner

🎨 Leonie Voss — UI/UX Design Lead

Observations

This issue is entirely a git history and configuration hygiene task — no UI/UX surface is affected. SKILL.md is an internal Claude skill document, UserDataInitializer.java controls seeded data, and application.yaml controls startup configuration. None of these produce user-visible output.

I have no design findings for this issue. The credential exposure does not create any user-facing UX failure — the risk is entirely operational (unauthorized admin access if the default password reaches a live deployment).

One tangential note from a user experience of the system perspective: If a developer accidentally deploys with admin123 as the password and an attacker gains admin access, they could modify documents, delete family history, or change user permissions. The UX consequence of that attack is severe — irreversible data loss for the family. This is a reason to prioritize the companion issue #83 (fail-fast startup when APP_ADMIN_PASSWORD is unset) alongside this scrub, not to delay it.

Recommendations

  1. No UI changes required for this issue.
  2. After #83 lands, update docs/DEPLOYMENT.md to remove the admin123 default reference from the onboarding checklist and replace it with clear instructions for generating a strong password — this is a UX concern for the developer experience (onboarding clarity), not the end-user experience.
  3. No Open Decisions from a UX perspective.
## 🎨 Leonie Voss — UI/UX Design Lead ### Observations This issue is entirely a git history and configuration hygiene task — no UI/UX surface is affected. `SKILL.md` is an internal Claude skill document, `UserDataInitializer.java` controls seeded data, and `application.yaml` controls startup configuration. None of these produce user-visible output. I have no design findings for this issue. The credential exposure does not create any user-facing UX failure — the risk is entirely operational (unauthorized admin access if the default password reaches a live deployment). **One tangential note from a user experience of the system perspective:** If a developer accidentally deploys with `admin123` as the password and an attacker gains admin access, they could modify documents, delete family history, or change user permissions. The UX consequence of that attack is severe — irreversible data loss for the family. This is a reason to prioritize the companion issue #83 (fail-fast startup when `APP_ADMIN_PASSWORD` is unset) alongside this scrub, not to delay it. ### Recommendations 1. **No UI changes required for this issue.** 2. After #83 lands, update `docs/DEPLOYMENT.md` to remove the `admin123` default reference from the onboarding checklist and replace it with clear instructions for generating a strong password — this is a UX concern for the developer experience (onboarding clarity), not the end-user experience. 3. No Open Decisions from a UX perspective.
Author
Owner

🗳️ Decision Queue — Consolidated Open Decisions

Two genuine tradeoffs raised across the review require a human call.


D1 — Scope of expressions.txt: narrow (per-file) vs. broad (global string replace)

Raised by: Nora (Security), Markus (Architect)

The tradeoff:

  • Broad replace (admin123 ==> $ADMIN_PASS globally across all history): one-shot, catches everything including files not yet identified. Side effect: rewrites commits in security_expert.md and devops.md where admin123 appears as a deliberate bad-example in the persona documentation, changing the meaning of those documents.

  • Narrow replace (scoped to --path .claude/skills/transcribe/SKILL.md --path README.md --path docs/TODO-backend.md): requires one filter-repo invocation per file path (or a combined --path list), but leaves intentional counter-examples in persona files untouched.

Recommendation: Use the narrow approach. Add --path flags for exactly the files that contain credentials-as-credentials (not credentials-as-examples). The persona files are instructional; rewriting them creates documentation confusion and adds unnecessary rewrites to commits that were correct.


D2 — README.md treatment: fix here or in #83?

Raised by: Nora (Security), Markus (Architect)

The tradeoff:

README.md:60 currently reads Password: admin123 as the documented dev default. This line should change, but when:

  • Fix here (this issue): Replace immediately with Password: [set via APP_ADMIN_PASSWORD in .env]. Closes the tracked-file exposure now. Leaves a slightly misleading README until #83 removes the Spring fallback.
  • Fix in #83: The README change makes most sense after the Spring property default is removed — the new text would point to APP_ADMIN_PASSWORD as the only source of truth, which is only true after #83 lands.

Recommendation: Fix the literal in README.md here (it is a tracked file with the credential in history that gitleaks will flag), but scope the messaging update — replace admin123 with a placeholder now, and update the surrounding onboarding text (what to set, where to set it) in #83 when the default is removed. The two-pass approach is slightly more work but keeps each issue self-contained.

## 🗳️ Decision Queue — Consolidated Open Decisions Two genuine tradeoffs raised across the review require a human call. --- ### D1 — Scope of `expressions.txt`: narrow (per-file) vs. broad (global string replace) **Raised by:** Nora (Security), Markus (Architect) **The tradeoff:** - **Broad replace** (`admin123 ==> $ADMIN_PASS` globally across all history): one-shot, catches everything including files not yet identified. Side effect: rewrites commits in `security_expert.md` and `devops.md` where `admin123` appears as a *deliberate bad-example* in the persona documentation, changing the meaning of those documents. - **Narrow replace** (scoped to `--path .claude/skills/transcribe/SKILL.md --path README.md --path docs/TODO-backend.md`): requires one `filter-repo` invocation per file path (or a combined `--path` list), but leaves intentional counter-examples in persona files untouched. **Recommendation:** Use the narrow approach. Add `--path` flags for exactly the files that contain credentials-as-credentials (not credentials-as-examples). The persona files are instructional; rewriting them creates documentation confusion and adds unnecessary rewrites to commits that were correct. --- ### D2 — README.md treatment: fix here or in #83? **Raised by:** Nora (Security), Markus (Architect) **The tradeoff:** `README.md:60` currently reads `Password: admin123` as the documented dev default. This line should change, but when: - **Fix here (this issue):** Replace immediately with `Password: [set via APP_ADMIN_PASSWORD in .env]`. Closes the tracked-file exposure now. Leaves a slightly misleading README until #83 removes the Spring fallback. - **Fix in #83:** The README change makes most sense after the Spring property default is removed — the new text would point to `APP_ADMIN_PASSWORD` as the only source of truth, which is only true after #83 lands. **Recommendation:** Fix the literal in README.md here (it is a tracked file with the credential in history that `gitleaks` will flag), but scope the messaging update — replace `admin123` with a placeholder now, and update the surrounding onboarding text (what to set, where to set it) in #83 when the default is removed. The two-pass approach is slightly more work but keeps each issue self-contained.
Sign in to join this conversation.
No Label P1-high security
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#460