On this page
You’re building a knowledge base that documents your whole lab. The temptation to paste “the Proxmox token, so it’s handy” into a note is enormous. Resist it completely, from your very first commit — because a knowledge base is the worst place to keep a secret. This is a ⚠️-flagged post in the series for a reason: this is a mistake that’s genuinely painful to undo.
Never commit a secret value to your vault. Store the value in a purpose-built secret store; put only a pointer — the variable name and its location — in your notes. Git never forgets, so a secret committed once is a secret you must rotate.
The examples use stand-ins — replace them with your own. /root/.myofficelab-secrets → wherever you keep your secret store; PROXMOX_API_TOKEN_ID/_SECRET → your actual variable names; CHANGE_ME and the-leaked-secret-value → your real values (which live in the store, never in a note). Never paste a real secret into an example just because a placeholder is sitting there.
Why a knowledge base is uniquely bad for secrets
The whole point of the vault is that it gets copied and projected everywhere. That’s a feature for knowledge and a catastrophe for credentials. This isn’t a niche concern — hard-coded credentials are catalogued as CWE-798 by MITRE, and OWASP’s Secrets Management Cheat Sheet gives the same guidance this post does: keep secrets out of source and reference them from a dedicated store. Trace where a single note travels:
Delete the secret from the note tomorrow and it still lives in Git history, in last night’s backup, and possibly in a search index that already embedded it. One paste, five places to clean.
The right pattern: pointers, not values
Keep credentials in a purpose-built store and reference them by name. In my lab the store is a single root-only file on one host, and every note that needs a credential names the variable, never the value.
# /root/.myofficelab-secrets — chmod 600, outside any repo
PROXMOX_API_TOKEN_ID=youruser@pve!app-token
PROXMOX_API_TOKEN_SECRET=CHANGE_ME
GRAFANA_API_KEY=CHANGE_ME
## Proxmox API access
Token lives as PROXMOX_API_TOKEN_ID / PROXMOX_API_TOKEN_SECRET
in /root/.myofficelab-secrets on the ops host. PVEAdmin role.
Do not paste the secret here.
If an app reads the vault-documented service, store its secret in an OS keystore (libsecret / GNOME Keyring on Linux, Keychain on macOS) or a dedicated manager like Vaultwarden. The note still only records the variable name and which store holds it.
Legitimate access resolves the pointer in seconds; the note stays safe to mount, mirror, publish, and index.
Prevention: a guard that refuses the commit
Make it hard to commit a secret by accident. A pre-commit hook that greps staged content for obvious secret shapes turns a silent mistake into a blocked commit.
cat > .git/hooks/pre-commit <<'EOF'
#!/bin/bash
# Block commits that look like they contain secrets.
if git diff --cached -U0 | grep -nEi \
'(api[_-]?key|token|secret|password|passwd|BEGIN [A-Z ]*PRIVATE KEY)[[:space:]]*[:=]' \
| grep -v 'CHANGE_ME'; then
echo "✋ Possible secret in staged changes — commit blocked."
echo " Store the value in your secret store; commit only a variable-name pointer."
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
This catches the obvious mistakes — an assignment that looks like a credential. It won’t catch a bare high-entropy string with no label. Use a dedicated scanner like gitleaks for real coverage; the hook is your cheap first line.
⚠️ Recovery: you already committed a secret
If a secret is already in your history, deleting it in a new commit is not enough — it’s still one command away in the history. You must rewrite history and rotate the credential. GitHub’s own guidance on removing sensitive data says exactly this: purge every commit and treat the credential as compromised.
Before touching Git, invalidate the exposed secret at its source — regenerate the API token, change the password. Assume it leaked. This is the step people skip and regret.
git-filter-repo is the modern, recommended tool for rewriting history:
# Install (Debian/Ubuntu): sudo apt-get install -y git-filter-repo
# Replace every occurrence of the leaked value across ALL commits
echo 'the-leaked-secret-value==>REDACTED' > /tmp/replacements.txt
git filter-repo --replace-text /tmp/replacements.txt
To remove an entire file that should never have been tracked:
git filter-repo --path secrets.env --invert-paths
git push --force --all
git push --force --tags
Every existing clone and mount now has divergent history — re-clone them fresh. Anyone who pulled the bad history must discard their copy. This blast radius is exactly why prevention beats recovery.
The full copy-paste recovery sequence is in the paired playbook: Vault Secret Store + History Scrub.
Other hosts, same rule
GitHub/GitLab hosted: enable native push protection / secret scanning — it blocks known secret formats at push time. Any Git host: gitleaks as a pre-commit hook or CI step is tool-agnostic. Secret store choice: a root-only file is the minimum; HashiCorp Vault, Bitwarden/Vaultwarden, or your OS keystore are all valid — the note-side rule (pointer, never value) is identical regardless.
What this buys you
The vault is now safe to publish and mirror, because the one class of content that must never leak is structurally kept out of it. With that settled, the next post makes the vault smart: turning a flat pile of pages into a connected graph, modeling knowledge as a brain.
Related posts:
- Never Lose a Homelab Note Again: A Git + Markdown Vault — the substrate this discipline protects
- Your Homelab Needs a Second Brain — Here’s Why — why the vault gets copied everywhere in the first place
- Turn a Pile of Notes Into a Connected Brain — the next step: connect the pages into a graph
- Why Auto-Syncing Your Notes Repo Will Corrupt It — where the commit-time secret scan is enforced
- Already Made a Mess of Your Notes? Here’s the Fix — the rotate-and-purge step as part of a full cleanup
- Vaultwarden on Proxmox LXC: Self-Hosted Password Manager — a real secret store to point your notes at
- Proxmox Security Hardening — securing the hosts your secret store lives on
Comments
Comments are powered by GitHub Discussions — sign in with a GitHub account to join the conversation.