← Writing

Already Pushed

2 min read#Redaction#Git#Release

The first commit of a public repo carried 272 things that should never have left the machine. Even after rewriting history they were still reachable by address.

While preparing a public repo I ran a redaction pass over its initial commit and got 272 hits: real names and nicknames, several chat accounts, a conversation identifier, a domain of my own, local network addresses, dates of personal events, and a handful of category names I would rather not spell out. They were scattered across config, fixtures, and diary material, and each one looked unremarkable on its own.

The remedy was rewriting that stretch of history and force-pushing. When it was done I checked, and locally the old commit was genuinely gone.

It could still be opened, though. The hosting platform keeps a reference for every pull request that has ever existed, and that reference still pointed at the old object. Anyone holding the address could read the pre-rewrite content in full.

Luck was on my side: zero stars, zero forks, zero watchers, so deleting and recreating cost almost nothing, which is what I did. Had anyone already forked it, deletion would no longer have been available, and the only path left would have been asking the platform to purge its cache, during which the exposure window belongs to somebody else.

I changed two things afterwards. Publishing now runs through a script carrying an allowlist and an exclusion table rather than a judgement call, made on the spot, about which files may leave. And redaction became a check you can actually run: scan for keywords before every release and refuse to continue on any non-zero hit count.

I went with an allowlist because I had tried a blocklist: it needs me to know in advance what the sensitive strings look like, and they turn up in a different form every time. An allowlist is simpler — any file not on the list stays home.

Written byShihao Qi