fix(redfix): STATUS/BACKLOG — TWO exposed live credentials, sweep regenerates them WEEKLY (both corrections conceded to Adversary)
Adversary wake #55 conceded my insteadOf falsification but corrected me twice; verified both first-hand: 1. "Production CI does not regenerate / manual-* = hand-run" WRONG. run_id()=manual-<pid> for any non-Drone run (run_recipe_ci.py:318-319); nightly-sweep runs run_recipe_ci.py outside Drone with CCCI_SKIP_FETCH=1 (nightly_sweep.py:88). Sweep regenerates the exposed copies WEEKLY (freshest 07-05 03:37-59 = sweep fire). 2. Census missed a 2nd credential (grep keyed on autonomic-bot: cannot see oauth2:). Full per-file census: 78 files carry the password, 117 a live oauth2 token, 62 both, 133 distinct under /var/lib. Token is LIVE + PUSH-capable (api/v1/user->200 autonomic-bot/64) and is what recipe-mirror-sync.sh:39 pushes with — falsifies my own B-redfix-8 "small blast radius" note. STATUS steps 3-4 rewritten (two creds, weekly regen, combined remedy + chmod 0750); B-redfix-8/9 corrected. DONE stands; no VETO; no DoD item touched; rotation of BOTH secrets remains operator-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y9GyBPF1EgTTh6277Xjj7k
This commit is contained in:
@@ -113,10 +113,29 @@ action that actually revokes the exposure.
|
||||
ssh cc-ci 'git -C /etc/cc-ci remote set-url origin \
|
||||
https://git.autonomic.zone/recipe-maintainers/cc-ci.git && chmod 600 /etc/cc-ci/.git/config'
|
||||
|
||||
**CORRECTION (wake #54, Builder, 2026-07-09T10:2xZ): `/etc/cc-ci/.git/config` is 1 of 78 world-readable
|
||||
copies — step 3 alone fixes 1/78.** The "sole copy" claim above is **withdrawn** (Adversary falsified it
|
||||
independently, REVIEW/BACKLOG wake #53). Scope, re-derived first-hand — 78 world-readable cred-bearing
|
||||
`.git/config`, all carrying sentinel `3fcea78925015fc9` (= the same live password):
|
||||
**CORRECTION (wake #54→#55, Builder, 2026-07-09): `/etc/cc-ci/.git/config` is 1 of many world-readable
|
||||
copies of TWO live credentials — step 3 alone fixes 1.** The "sole copy" claim above is **withdrawn**.
|
||||
Scope re-derived first-hand at wake #55 (a full-FS, per-file census — my wake-#54 count of 78 was BOTH
|
||||
undercounted AND single-credential; Adversary flagged both, wake #55). Two distinct live credentials, each
|
||||
its own `sha256(pw)[:16]` sentinel (empty-input control `e3b0c44298fc1c14`):
|
||||
|
||||
| credential | sentinel | world-readable copies (uid-1000-readable) |
|
||||
|---|---|---|
|
||||
| `autonomic-bot` **password** (B-redfix-8) | `3fcea78925015fc9` | 78 (68 run-dir + 8 `/nix/store` 0444 + `/tmp/v` + `/etc/cc-ci`) |
|
||||
| `oauth2` **Gitea token** (NEW, wake #55) | `9c44a1aea2ecb389` | 117 (`/var/lib/cc-ci-runs`), sourced from 20 canonical clones |
|
||||
|
||||
Per-file under `/var/lib/cc-ci-runs`: **62 carry BOTH**, 16 password-only, 55 token-only → **133 distinct
|
||||
world-readable cred-bearing files** there. **The `oauth2` token is LIVE and PUSH-CAPABLE** — verified
|
||||
`GET /api/v1/user` → 200 `login=autonomic-bot id=64`, and `recipe-mirror-sync.sh:39` pushes with it
|
||||
(`https://oauth2:<TOKEN>@…`). So **both** secrets must be rotated, not just `GITEA_PASSWORD`. Re-census:
|
||||
|
||||
ssh cc-ci 'find / -xdev -name config -path "*/.git/*" 2>/dev/null | while read f; do
|
||||
setpriv --reuid=1000 --regid=1000 --clear-groups cat "$f" >/dev/null 2>&1 || continue
|
||||
grep -qE "autonomic-bot:|oauth2:" "$f" && echo "$f"; done | wc -l'
|
||||
# EXPECTED: ~135 today (133 in /var/lib + /tmp/v + /etc/cc-ci); after remediation: 0 (ignoring 0444 /nix/store)
|
||||
|
||||
Legacy list (password only), retained for the step-3 command below — the `origin` in these carries the
|
||||
password sentinel `3fcea78925015fc9`:
|
||||
**68** under `/var/lib/cc-ci-runs/manual-*/abra/recipes/*/`, **8** in `/nix/store` (0444, read-only, clears
|
||||
on GC), **1** `/tmp/v`, **1** `/etc/cc-ci`. Verify:
|
||||
|
||||
@@ -125,16 +144,26 @@ action that actually revokes the exposure.
|
||||
setpriv --reuid=1000 --regid=1000 --clear-groups cat "$f" >/dev/null 2>&1 && echo "$f"; done | wc -l'
|
||||
# EXPECTED: 78 (after remediation: 0, ignoring /nix/store)
|
||||
|
||||
4. **Scrub the other 77 (A-redfix-1, widened).** The generator is the **credentialed `origin` in the canonical
|
||||
clones** `/root/.abra/recipes/*/.git/config`, which `fetch_recipe`'s `CCCI_SKIP_FETCH=1` staging path
|
||||
(`runner/run_recipe_ci.py:348-353`, `shutil.copytree`) copies into the world-traversable run tree
|
||||
(`/var/lib/cc-ci-runs`, `0755`). The canonical copies are themselves shielded by `/root` = `0700`; the
|
||||
run-dir copies are not. Strip userinfo at the source, then scrub the copies:
|
||||
4. **Scrub the copies AND stop regeneration (A-redfix-1, widened).** The generator is the **credentialed
|
||||
remotes in the canonical clones** `/root/.abra/recipes/*/.git/config` (password on `origin`, oauth2 token
|
||||
on the `gitea`/mirror remote), which `run_recipe_ci.py:348-353`'s `CCCI_SKIP_FETCH=1` `shutil.copytree`
|
||||
copies into the world-traversable run tree (`/var/lib/cc-ci-runs`, `0755`). Canonicals are shielded by
|
||||
`/root` = `0700`; the run-dir copies are not.
|
||||
**REGENERATES WEEKLY (corrected wake #55).** The `manual-*` run dirs are NOT hand-run leftovers: the
|
||||
autonomous `nightly-sweep.timer` runs `run_recipe_ci.py` outside Drone (`nightly_sweep.py:88` sets
|
||||
`CCCI_SKIP_FETCH="1"`), and `run_id()` labels any non-Drone run `manual-<pid>` (`run_recipe_ci.py:318-319`).
|
||||
So the sweep re-creates these copies every fire (freshest copies dated 2026-07-05 03:37–03:59Z = the
|
||||
`LastTriggerUSec` 2026-07-05 03:04:50Z sweep). **A one-time scrub is re-exposed on the next sweep unless
|
||||
the canonical origins are stripped or `/var/lib/cc-ci-runs` is hardened to `0750` durably.** Strip **both**
|
||||
credentials at the source, then scrub the copies:
|
||||
|
||||
ssh cc-ci 'for d in /root/.abra/recipes/*/; do r=$(basename "$d");
|
||||
git -C "$d" remote set-url origin https://git.autonomic.zone/recipe-maintainers/$r.git 2>/dev/null; done
|
||||
for rem in origin gitea upstream; do
|
||||
git -C "$d" remote get-url "$rem" >/dev/null 2>&1 || continue
|
||||
git -C "$d" remote set-url "$rem" "$(git -C "$d" remote get-url "$rem" | sed -E "s#://[^@/]+@#://#")"; done; done
|
||||
rm -rf /tmp/v
|
||||
find /var/lib/cc-ci-runs -path "*/.git/config" -exec grep -lq "autonomic-bot:" {} \; -delete'
|
||||
find /var/lib/cc-ci-runs -path "*/.git/config" \( -exec grep -lq "autonomic-bot:" {} \; -o -exec grep -lq "oauth2:" {} \; \) -delete
|
||||
chmod 0750 /var/lib/cc-ci-runs'
|
||||
|
||||
Stripping the userinfo does **not** break the clone: the sweep only ever *fetches*, and the mirror serves
|
||||
this repo anonymously (that is precisely what B-redfix-8 exploits). Verified 2026-07-09T09:1xZ —
|
||||
|
||||
Reference in New Issue
Block a user