Version. 0.1 Date. 2026-07-18 Author. Claude Code on DUNIN7-M4, on Operator direction. Status. QUEUED. Post-Stage-1 work item, not started. Filed with the perimeter Stage 1 documents.
Two credential exposures have now been found on DUNIN7-M4 by accident, in unrelated work, four weeks apart. Neither was found by looking. That is the argument for looking deliberately once, rather than waiting for a third.
The pattern is the finding, not the files: plaintext credentials in configuration that nothing treats as a secret. Both instances were world-readable, and one of them stayed that way for roughly three months.
Instance 1 — ~/Library/LaunchAgents/com.dunin7.foraychallenge.plist. Found 2026-07-18 while reading the file as the house LaunchAgent precedent for the perimeter build's persistent-run design. Mode -rw-r--r-- (world-readable) with a plaintext Anthropic API key in its EnvironmentVariables block. Exposure ran from 10 April to 18 July 2026 — roughly three months — ended by revocation. Resolved the same night: key revoked in the console, replacement issued and verified, file tightened to 600.
Instance 2 — /Users/dunin7/loomworks/.dev.vars. Recorded in the perimeter session handoff §7, 2026-07-18. Mode -rw-r--r-- with an Anthropic key. Git-ignored and untracked, so never in history, and likely vestigial since the engine resolves keys from the database rather than the environment. Still open — an Operator rotation decision, non-blocking.
Corroborating evidence from the incident's handling. Rotating instance 1 required hand-editing a plist in nano, which corrupted line 1 of the file and briefly produced a mangled value that looked like a third key. The reconciliation cost real time and produced a false alarm. That friction is itself evidence: hand-edited plaintext secrets in configuration files are hard to rotate correctly, so they tend not to be rotated at all.
Note also the inconsistency within one directory: com.dunin7.minio.plist is mode 600 while com.dunin7.foraychallenge.plist was 644. There is no enforced convention — only whatever each file's author happened to do.
~/Library/LaunchAgents/*.plist, every .env / .dev.vars / .envrc across the DUNIN7 repositories, and any standalone scripts with inline keys. The check is mechanical: mode, and whether the contents are plaintext secrets..dev.vars. Confirm it is genuinely vestigial, then delete it rather than tightening it — an unused secret is best removed, not secured.The key rotation is an Operator action, not an engineering one, and the procedure is the same as instance 1's rotation on 2026-07-18: revoke the exposed key in the Anthropic console, issue a replacement, verify the replacement against a real call before relying on it, and only then remove or tighten the file. Order matters — revoking before the replacement is verified takes the dependent service down, and tightening the file first leaves an exposed-but-live key in place, which is the worse of the two failure modes.
Note the one procedural lesson from that rotation: do not hand-edit the file to swap the value. Editing the plist in nano corrupted its first line and produced a mangled string that looked like a third key, costing a reconciliation pass and raising a false alarm. If a value must be replaced in place, rewrite the file programmatically and verify it parses before loading it.
WorkingDirectory so the service reads a mode-600 .env instead. That is a candidate pattern already in production use.
Rotating keys that are not exposed, and any change to how the engine resolves API keys (it already reads them from the database via resolve_engagement_api_key, which is the correct posture and not implicated).
Both instances were found while doing something else. Case-by-case handling has already produced one three-month exposure, and there is no reason to believe the discovery rate reflects the actual rate. A single deliberate pass over a known, small set of locations converts an unknown into a list.
DUNIN7 — Done In Seven LLC — Miami, Florida DUNIN7 — secrets-hygiene sweep — queue item — v0_1 — 2026-07-18