Two commits, both consequences of a live Gitea site-admin token having been committed as a test fixture in 9b2f4fe (2026-08-11) and sitting in the public GitHub mirror for fourteen days. The token has been revoked and the API confirms 401.
d09e2a2 — stop using a live credential as a test fixture
the_custom_env_fingerprint_never_carries_the_value asserted that the fingerprint does not leak a secret, using the real one as the input. The fixture is now obviously fake.
Mutation-checked against the replacement, because the natural worry is that swapping the value weakens the test: a fingerprint that returns the raw value, one that returns the key name, and one that ignores its input are all still caught. Nothing about the test ever depended on the value being real.
Release bundles were never affected — the literal is inside #[cfg(test)], and a search of the shipped 0.4.62 AppImage finds nothing.
History is deliberately not rewritten. The value was public for two weeks, so rotation is the fix and the old value is now worthless; rewriting 92 commits of published history would break every clone to hide something already seen.
68b73a9 — refuse a commit that adds something shaped like a credential
Three rules: vendor-prefixed tokens, BEGIN … PRIVATE KEY blocks, and an opaque literal assigned to a secret-shaped name. That third one needs both halves — measured first, an entropy-only rule flags 317 literals in this tree and name-proximity alone flags four, three of which are the keychain key name aws-secret-access-key.
Validated, not asserted:
0 false positives across every tracked file
catches the real incident when 9b2f4fe is replayed
twelve shaped cases behave correctly, including a sha256 in an assert_eq! and a git sha in a comment
the hook was proved to block an actual git commit
Two halves: .githooks/pre-commit (fast, opt-in per clone via npm run hooks, skippable with --no-verify) and a Secret Scan workflow that nobody can bypass. The workflow carries no paths: filter on purpose — the leak lived in app/** and build.yml only runs for container/**, so a path-filtered scan would have missed the very thing it exists for.
Also fixed: core.hooksPath pointed at a directory that does not exist, so git hooks were disabled outright in this clone. Anything dropped in .git/hooks would have been ignored in silence.
Worth deciding separately
A high-entropy check would not have caught this on its own, and neither did five audit rounds — every review was pointed at the code under change. If more of this class is a concern, the next lever is scanning history on a schedule rather than only new commits.
Two commits, both consequences of a live Gitea **site-admin** token having been committed as a test fixture in `9b2f4fe` (2026-08-11) and sitting in the public GitHub mirror for fourteen days. The token has been revoked and the API confirms 401.
### `d09e2a2` — stop using a live credential as a test fixture
`the_custom_env_fingerprint_never_carries_the_value` asserted that the fingerprint does not leak a secret, using the real one as the input. The fixture is now obviously fake.
Mutation-checked against the replacement, because the natural worry is that swapping the value weakens the test: a fingerprint that returns the raw value, one that returns the key name, and one that ignores its input are all still caught. Nothing about the test ever depended on the value being real.
Release bundles were never affected — the literal is inside `#[cfg(test)]`, and a search of the shipped 0.4.62 AppImage finds nothing.
History is deliberately **not** rewritten. The value was public for two weeks, so rotation is the fix and the old value is now worthless; rewriting 92 commits of published history would break every clone to hide something already seen.
### `68b73a9` — refuse a commit that adds something shaped like a credential
Three rules: vendor-prefixed tokens, `BEGIN … PRIVATE KEY` blocks, and an opaque literal assigned to a secret-shaped name. That third one needs **both** halves — measured first, an entropy-only rule flags 317 literals in this tree and name-proximity alone flags four, three of which are the keychain key name `aws-secret-access-key`.
Validated, not asserted:
- **0 false positives** across every tracked file
- **catches the real incident** when `9b2f4fe` is replayed
- twelve shaped cases behave correctly, including a sha256 in an `assert_eq!` and a git sha in a comment
- the hook was proved to block an actual `git commit`
Two halves: `.githooks/pre-commit` (fast, opt-in per clone via `npm run hooks`, skippable with `--no-verify`) and a `Secret Scan` workflow that nobody can bypass. The workflow carries **no `paths:` filter** on purpose — the leak lived in `app/**` and `build.yml` only runs for `container/**`, so a path-filtered scan would have missed the very thing it exists for.
Also fixed: `core.hooksPath` pointed at a directory that does not exist, so git hooks were disabled outright in this clone. Anything dropped in `.git/hooks` would have been ignored in silence.
### Worth deciding separately
A high-entropy check would not have caught this on its own, and neither did five audit rounds — every review was pointed at the code under change. If more of this class is a concern, the next lever is scanning history on a schedule rather than only new commits.
`the_custom_env_fingerprint_never_carries_the_value` asserted that the custom-env
fingerprint does not leak a secret — using the maintainer's real Gitea token as
the secret. It was committed on 2026-08-11 in 9b2f4fe, reached 92 commits, and
was readable for fourteen days in the public GitHub mirror at
`shadowdao/triple-c`, confirmed by fetching the raw file.
The token was a **site-admin** token (`is_admin: true`, user id 1) with admin
rights on every repository the account can see, not a repo-scoped one. It has
been revoked; the API now answers 401.
Release bundles were never affected — the literal is inside `#[cfg(test)]`, and
a search of the shipped 0.4.62 AppImage finds nothing.
The fixture is now an obviously fake string, and the test is unchanged
otherwise. Mutation-checked against the replacement: a fingerprint that returns
the raw value, one that returns the key name, and one that ignores its input are
all still caught, so nothing about the test's power depended on the value being
real — which was true the whole time.
History is deliberately **not** rewritten. The value was public for two weeks, so
rotation is the fix and the old value is now worthless; rewriting 92 commits of
published history would break every clone to hide something already seen.
Worth noting how this survived: five audit rounds and two independent reviews
all pointed at new code, and this sat in a test file that none of them had reason
to open. A high-entropy-literal check in CI would have caught it on the day.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHL9ty7arp8FHwvE77ne7y
The companion to the fixture removal. A site-admin token sat in a test file for
92 commits and fourteen days on a public mirror, past five audit rounds and two
independent reviews, because all of them read the code under change and this was
not under change. A grep would have caught it the first day.
`scripts/scan-secrets.sh` is that grep, in three rules:
* vendor-prefixed credentials — `ghp_`, `github_pat_`, `glpat-`, `xox*-`,
`sk-`, `AKIA`/`ASIA`, `ya29.`, `AIza`, `npm_`, `dckr_pat_`. Shape alone
identifies these, so there is no context to get wrong.
* `BEGIN … PRIVATE KEY` blocks.
* an opaque literal assigned to a secret-shaped name — the rule that would
have caught this one.
The third rule needs **both** halves, and that is what makes it usable rather
than another disabled check. Measured before writing it: an entropy-only rule
flags 317 literals in this tree, and name-proximity alone flags four, three of
which are `secure::get_project_secret(&id, "aws-secret-access-key")` — a
keychain *key name* sitting next to the word `secret`. Requiring the literal
itself to be hex or base64 with no word structure is what excludes those.
Validated rather than asserted:
* **0 false positives** across every tracked file.
* **Catches the real incident** — `--range 9b2f4fe~1..9b2f4fe` is refused.
* Twelve shaped cases pass and fail as intended, including a sha256 in an
`assert_eq!`, a git sha in a comment and the new dummy fixture, none of
which trip it.
* The hook was proved to block an actual `git commit`, not just to exist.
Two halves, because each covers the other's gap:
* `.githooks/pre-commit`, enabled per clone by `npm run hooks`. Git will not
let a repository set its own hooks path — cloning would then be enough to
run its code — so this is opt-in everywhere and `--no-verify` skips it.
* `Secret Scan`, which nobody can bypass. It carries **no `paths:` filter** on
purpose: the leak lived in `app/**` and `build.yml` only runs for
`container/**`, so a path-filtered scan would have missed the very thing it
exists for. It scans the whole tracked tree rather than a range, because a
wrong range fails *open* and the full pass takes 0.5s.
Also fixed while here: `core.hooksPath` in this clone pointed at
`/workspace/.git/hooks`, a directory that does not exist — so git hooks were
disabled outright and anything dropped in `.git/hooks` would have been ignored
in silence. A hook that never runs is worse than no hook, because the checklist
says it is there.
`--tracked` skips binaries. Feeding a blob to grep gets "binary file matches"
instead of the line, so a genuine finding inside one would arrive as a sentence
nobody can act on.
A line ending `pragma: allowlist secret` is skipped — wordy on purpose, so it
reads as a claim and leaves something greppable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHL9ty7arp8FHwvE77ne7y
jknapp
merged commit 1a79852f65 into main2026-08-25 18:54:56 +00:00
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.
Two commits, both consequences of a live Gitea site-admin token having been committed as a test fixture in
9b2f4fe(2026-08-11) and sitting in the public GitHub mirror for fourteen days. The token has been revoked and the API confirms 401.d09e2a2— stop using a live credential as a test fixturethe_custom_env_fingerprint_never_carries_the_valueasserted that the fingerprint does not leak a secret, using the real one as the input. The fixture is now obviously fake.Mutation-checked against the replacement, because the natural worry is that swapping the value weakens the test: a fingerprint that returns the raw value, one that returns the key name, and one that ignores its input are all still caught. Nothing about the test ever depended on the value being real.
Release bundles were never affected — the literal is inside
#[cfg(test)], and a search of the shipped 0.4.62 AppImage finds nothing.History is deliberately not rewritten. The value was public for two weeks, so rotation is the fix and the old value is now worthless; rewriting 92 commits of published history would break every clone to hide something already seen.
68b73a9— refuse a commit that adds something shaped like a credentialThree rules: vendor-prefixed tokens,
BEGIN … PRIVATE KEYblocks, and an opaque literal assigned to a secret-shaped name. That third one needs both halves — measured first, an entropy-only rule flags 317 literals in this tree and name-proximity alone flags four, three of which are the keychain key nameaws-secret-access-key.Validated, not asserted:
9b2f4feis replayedassert_eq!and a git sha in a commentgit commitTwo halves:
.githooks/pre-commit(fast, opt-in per clone vianpm run hooks, skippable with--no-verify) and aSecret Scanworkflow that nobody can bypass. The workflow carries nopaths:filter on purpose — the leak lived inapp/**andbuild.ymlonly runs forcontainer/**, so a path-filtered scan would have missed the very thing it exists for.Also fixed:
core.hooksPathpointed at a directory that does not exist, so git hooks were disabled outright in this clone. Anything dropped in.git/hookswould have been ignored in silence.Worth deciding separately
A high-entropy check would not have caught this on its own, and neither did five audit rounds — every review was pointed at the code under change. If more of this class is a concern, the next lever is scanning history on a schedule rather than only new commits.
The companion to the fixture removal. A site-admin token sat in a test file for 92 commits and fourteen days on a public mirror, past five audit rounds and two independent reviews, because all of them read the code under change and this was not under change. A grep would have caught it the first day. `scripts/scan-secrets.sh` is that grep, in three rules: * vendor-prefixed credentials — `ghp_`, `github_pat_`, `glpat-`, `xox*-`, `sk-`, `AKIA`/`ASIA`, `ya29.`, `AIza`, `npm_`, `dckr_pat_`. Shape alone identifies these, so there is no context to get wrong. * `BEGIN … PRIVATE KEY` blocks. * an opaque literal assigned to a secret-shaped name — the rule that would have caught this one. The third rule needs **both** halves, and that is what makes it usable rather than another disabled check. Measured before writing it: an entropy-only rule flags 317 literals in this tree, and name-proximity alone flags four, three of which are `secure::get_project_secret(&id, "aws-secret-access-key")` — a keychain *key name* sitting next to the word `secret`. Requiring the literal itself to be hex or base64 with no word structure is what excludes those. Validated rather than asserted: * **0 false positives** across every tracked file. * **Catches the real incident** — `--range 9b2f4fe~1..9b2f4fe` is refused. * Twelve shaped cases pass and fail as intended, including a sha256 in an `assert_eq!`, a git sha in a comment and the new dummy fixture, none of which trip it. * The hook was proved to block an actual `git commit`, not just to exist. Two halves, because each covers the other's gap: * `.githooks/pre-commit`, enabled per clone by `npm run hooks`. Git will not let a repository set its own hooks path — cloning would then be enough to run its code — so this is opt-in everywhere and `--no-verify` skips it. * `Secret Scan`, which nobody can bypass. It carries **no `paths:` filter** on purpose: the leak lived in `app/**` and `build.yml` only runs for `container/**`, so a path-filtered scan would have missed the very thing it exists for. It scans the whole tracked tree rather than a range, because a wrong range fails *open* and the full pass takes 0.5s. Also fixed while here: `core.hooksPath` in this clone pointed at `/workspace/.git/hooks`, a directory that does not exist — so git hooks were disabled outright and anything dropped in `.git/hooks` would have been ignored in silence. A hook that never runs is worse than no hook, because the checklist says it is there. `--tracked` skips binaries. Feeding a blob to grep gets "binary file matches" instead of the line, so a genuine finding inside one would arrive as a sentence nobody can act on. A line ending `pragma: allowlist secret` is skipped — wordy on purpose, so it reads as a claim and leaves something greppable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHL9ty7arp8FHwvE77ne7y