An external scanner sees your site the way a stranger does: the HTML, the JavaScript bundle, the headers, the exposed .env if you shipped one. It cannot see your git history, your local machine, or the transcripts of the AI assistant you build with. On 7 September 2026 we had a coding agent run the checkup that covers those places on one of our own repositories. This is what it found, masked, and what changed because of it.
What did the checkup find?
Answer. Eight issues, four of them high, in a repository whose public surface had passed every external check.
The last four are the kind of thing a database advisor or a dependency bot also reports. The first four are not visible to anything that looks at the repository from the outside.
How does a secret end up in an agent transcript?
Answer. By being typed, pasted or echoed in a session with a coding assistant. The transcript is a file on disk, and it syncs to the assistant's vendor.
The Google OAuth client secret in the table above was ours, from a different project. On 31 August one of our own sessions passed the value inline to a shell command instead of reading it from a file. The command ran fine. The value also landed in the transcript, in the command and in the tool output, six times. A week later the checkup on an unrelated repository found it, because on this machine every project's sessions start from the home directory and share one transcript folder.
That is two lessons in one line. A secret inside a command you run is as exposed as a secret you print. And "my project's transcripts" may be everyone's transcripts.
We rotated the client secret the same evening: new secret in the console, in the host's environment and in the auth provider that shares the client, then the old one disabled, then a login and a token refresh to prove the new one is in use.
Why is the git history the part people skip?
Answer. Because deleting the line feels like fixing it, and the diff says the secret is gone.
The Notion token was hard-coded in three scripts in February 2026. At some point the scripts were changed to read from the environment, and the current files are clean. Every clone of the repository still contains the February commits, and so does every fork and every CI cache. A token that has been in history for seven months should be treated as public.
The order of operations matters:
- Rotate the token with its provider. Until you do, the old value works for anyone who has it.
- Check the provider's usage log for the exposure window. Leaked keys are often already in use.
- Only then decide whether to rewrite history with
git filter-repo. In a private repository with three collaborators we chose not to: a history rewrite breaks every other clone, and the rotated token is worthless anyway.
What does a checkup like this actually run?
Answer. A list of commands the agent executes locally and reports back with counts, never with values.
git log --all --full-history -- .env .env.*to confirm the env files were never committed.gitleaks detectover the full history, orgit log -p --all | rgwith the same secret patterns when gitleaks is not installed.- A grep of the agent transcript folders for the same patterns and for the exact values of the current
.env(compared locally, never printed). - A grep of tracked source for hard-coded keys, skipping SQL, examples, docs and lockfiles.
- A check that no server-only variable is referenced in client code without a public prefix.
select tablename, rowsecurity from pg_tablesand the list ofSECURITY DEFINERfunctions with their grants, run against the project's own database.select id, public from storage.bucketsand whether public buckets are listable.npm audit --omit=dev --audit-level=high.
Every item the agent reports becomes an open finding in Moonleap with the masked location and a fix recipe, so it is closed the same way as everything else: the agent fixes it with the owner's approval, reports what changed, and the next checkup confirms it is gone.
What changed in how we work?
Answer. Three rules, all of them about the terminal.
- Secret values move by pipe, never by hand.
grep KEY .env | cut -d= -f2- | vercel env add KEY productionputs a value in place without it appearing anywhere a person or a transcript can read it. - Anything a session prints, pastes or passes inline is treated as exposed and rotated. Not "probably fine". Rotated.
- A scan that looks in shared places attributes what it finds. The checkup instructions now say that transcript folders may hold other projects' secrets, and that those are reported to the owner but kept out of the scanned project's record.
FAQ
Is a private repository enough to keep a hard-coded key safe?
No. Private means access-controlled, not secret. Collaborators, CI systems, backups and every laptop with a clone hold the full history.
Do AI assistant transcripts really leave the machine?
For hosted assistants, yes: the conversation is sent to the vendor to produce each answer, and most tools keep a local copy as well. Treat both copies as outside your control.
How often should the checkup run?
After any change to authentication, webhooks or database policies, and at least monthly. Moonleap's project settings let you pick the cadence and remind you when a deploy has happened since the last run.
Sources
- Repo security checkup on one of our own repositories, 7 September 2026, run by the owner's coding agent with the Moonleap checkup instructions (results masked, values never stored)
- gitleaks https://github.com/gitleaks/gitleaks
- git filter-repo https://github.com/newren/git-filter-repo
- Supabase, "SECURITY DEFINER functions" https://supabase.com/docs/guides/database/database-advisors