Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / docs/evidence/phase2/findings/finding-4-secret-sweep-out-of-repo.txt |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | docs/evidence/phase2/findings/finding-4-secret-sweep-out-of-repo.txt |
| Original SHA-256 | cbab4c66a02d57547cd83f9a13334a3c9d50562f1015432609b6cb2f5ed45b97 |
| Git blob SHA | 660d5b5162dc4f8deafe1ea3a31183ddd5b38e99 |
| Reading-copy SHA-256 | cbab4c66a02d57547cd83f9a13334a3c9d50562f1015432609b6cb2f5ed45b97 |
Recovered source transcript
Download complete source text ↓181 lines · 8.6 KB
FINDING FOUR, CLOSED BY EXECUTION
The secret sweep was blind outside the repository.
Run 29 July 2026 on megamind-agi WSL and Bubbles from the M4 working copy.
THE FINDING, RESTATED HONESTLY
tools/verify/secret-sweep/sweep.sh scanned the repository and reported "clean".
That sentence was true and it read as something much broader than it was.
Two of the five credential consumers broken by the D5 rotation lived in
/usr/local/sbin, which is not in the repository. One of them,
mm-restore-drill.sh, held a migrator password in PLAINTEXT for weeks. The
sweep could not have found it at any point, and it never said so. A clean
result meant clean in the repository and was read as clean.
WHAT WAS BUILT
outofrepo.scope 15 enumerated scopes, HOST tab KIND tab GLOB. Every line
traces to a section of docs/CREDENTIAL_CONSUMERS.md, to a
systemd unit carrying an EnvironmentFile, or to an ops
script. The scope is ENUMERATED, not discovered by walking
the disk, so the inventory and the sweep can be diffed
against each other and a consumer in one but not the other
is a defect in whichever is behind.
remote-scan.sh The remote half. Staged onto a host and run there.
sweep.sh --out-of-repo runs the enumerated scopes.
--control --out-of-repo controls every scope it claims.
THE ASSERTION IS REFERENCES, NOT ABSENCE
ENV FILES ARE THE STORE. /etc/missionmatch/*.env and backup.dsn are SUPPOSED
to hold values. They are checked for MODE ONLY, never content. Flagging them
would train the reader to ignore the sweep, and a sweep people ignore is worse
than no sweep because it also provides cover.
SCRIPTS AND UNITS MUST REFERENCE. A script names a variable or reads an env
file. It never embeds a value. That is exactly what mm-restore-drill.sh
violated. It is the assertion here.
NO VALUE IS EVER PRINTED
The remote half reports KIND, PATH, LINE, PATTERN NAME. Never the matched
text. grep runs with -n only, never in a mode that echoes the line. The
control mode counts findings and does not echo them even though its planted
value is fake.
This is not a hypothetical concern. This build disclosed a live credential
into a log this week through flag usage output, finding D14. A sweep that
echoes what it finds is a disclosure with good intentions.
WHAT IT FOUND ON ITS FIRST WORKING RUN
megamind:/usr/local/sbin/mm-identity-sync.sh line 16 dsn_with_password
megamind:/usr/local/sbin/mm-identity-sync.sh line 17 dsn_with_password
Two complete DSNs, passwords included, one per cluster, in a script a systemd
timer runs every hour as root.
docs/CREDENTIAL_CONSUMERS.md ALREADY DESCRIBED THESE TWO LINES AS A TRAP and
left them standing. The inventory knew. Nothing could see it, so nothing acted
on it, and that gap between knowing and seeing is the whole finding.
Verified before touching anything, values never printed:
the embedded tenant DSN and MM_TENANT_MIGRATOR_DSN_TENANT_ACME IDENTICAL
by salted hash
the embedded control DSN and MM_MIGRATOR_DATABASE_URL same user, SAME
PASSWORD by salted hash, differing only 127.0.0.1 against 100.77.114.40,
which is the same cluster reached two ways
both env DSNs connect from inside WSL
the hourly timer was healthy, Result=success, last run 2 minutes prior
So the repair was a substitution of equals, not a credential change.
THE REPAIR
mm-identity-sync.sh now sources /etc/missionmatch/db.env and resolves
MM_MIGRATOR_DATABASE_URL and MM_TENANT_MIGRATOR_DSN_TENANT_ACME, failing by
NAME if either is absent. A wrong credential and an absent one look identical
from the far side of a socket, and that ambiguity is what made the D5 rotation
take five separate discoveries instead of one.
IT ALSO LEFT argv. The old script passed both DSNs as command line flags to
psql and to sync-tenant-identity. argv is world readable through ps, so any
account on that host could read both migrator passwords out of the process
table for the length of a run. The Go binary already falls back to the same
two environment variables when its flags are empty, and psql reads the libpq
variables, so this cost nothing.
MEASURED BOTH WAYS, counts only, no values:
peak argv DSN exposures during a run of the REPAIRED script 0
peak argv DSN exposures during a run of the OLD script 1
The second number is the positive control. Without it the first proves only
that the sampler ran.
Verified after install: syntax clean, 750 root:root, and a real run
reconciled 7 control plane users against 7 in the tenant copy.
THE POSITIVE CONTROLS, ONE PER SCOPE, BOTH DIRECTIONS
A planted credential must be FOUND, and then must stop being reported once
removed. A check that always fires is as useless as one that never does, and
only the second direction distinguishes them.
control OK repo untracked planted credential detected, 1
control OK repo untracked, cleared clean once the plant was removed
control OK repo tracked planted credential detected, 1
control OK repo tracked, restored hash matches
control OK repo tracked, cleared clean once the plant was removed
control OK bubbles script planted DSN detected, 1
control OK bubbles unit inline unit secret detected, 2
control OK bubbles mode, loose world readable file flagged, 1
control OK bubbles mode, correct 0600 root owned correctly NOT flagged
control OK megamind script planted DSN detected, 1
control OK megamind unit inline unit secret detected, 2
control OK megamind mode, loose world readable file flagged, 1
control OK megamind mode, correct 0600 root owned correctly NOT flagged
positive control: 13 passed, 0 failed
TRACKED AND UNTRACKED, INSIDE AND OUTSIDE, as the order required. The tracked
control MODIFIES an already tracked file and never touches the index, because
staging a credential shaped string even briefly risks a crash leaving it
staged for the next commit. Its content is saved and restored and the restore
is VERIFIED BY HASH rather than assumed.
The mode control uses a file of its own at /etc/missionmatch/zz-sweep-control.env
so no real credential file's permissions are ever loosened to test the
instrument. Remote plants are removed by a TRAP rather than a trailing line,
because a control that plants a credential shaped file on a server and then
dies has created the problem it was testing for.
Cleanup verified after the control run: 3 of 3 plant paths absent on each
host, 0 dirty control paths in git.
TWO DEFECTS IN THE INSTRUMENT ITSELF, FOUND AND FIXED DURING THIS WORK
1. ssh CONSUMED THE SCOPE FILE. The scope loop read from the file on stdin and
ssh inherited it, so ssh drank the remaining 12 lines. Exactly ONE scope
ran and the sweep reported clean. Fixed with ssh -n.
The guard was ALSO wrong: it refused only when ZERO scopes answered, so one
scope out of thirteen satisfied it. It now counts the expected scopes out of
the file and refuses unless every one returns a summary. "At least one
answered" is not a check.
2. NESTED printf %q DID NOT SURVIVE THE WSL BRIDGE, so all five megamind
scopes failed to reach the host. The sweep correctly refused to report
clean for them, which is the guard working rather than a second defect. A
single unnested invocation survives.
THE COUNTED RUN
secret sweep: working tree
secret sweep: out of repo scope
out of repo: 15 of 15 enumerated scopes scanned, all answered
secret sweep: clean
WHAT THIS STILL DOES NOT CLAIM
The scope is 15 enumerated targets on two hosts. It does not cover VALKYRIE,
which is a backup target holding encrypted dumps and no scripts, and it does
not cover M4, which runs the databases and holds no ops scripts of its own.
Adding a host means adding scope lines, and the enumeration is deliberately
the thing you have to edit, so a new host cannot arrive silently unswept.
It reads files. It cannot see a credential that exists only in a running
process's memory, in a shell history, or in a systemd drop in nobody listed.
The argv measurement above was a separate deliberate check, not something the
file sweep does.
REPRODUCE
MM_MEGAMIND_PW=... bash tools/verify/secret-sweep/sweep.sh --control --out-of-repo
MM_MEGAMIND_PW=... bash tools/verify/secret-sweep/sweep.sh --out-of-repo
The control comes FIRST. A clean sweep whose control has not run this session
is an unverified instrument reporting a negative.