`fdroid update` writes a status/ directory containing update.json and
running.json, which record the absolute paths of the machine that built the
repo — home directory, username, toolchain locations — and that signing
happened there. My publish script rsynced the whole repo directory, so those
went public and were being served unauthenticated.
That is targeting data for a supply-chain attack against the laptop holding the
Android release key, which is permanent and cannot be rotated without orphaning
every install. fdroid's own deploy command excludes status/; a raw rsync does
not, and I used a raw rsync.
Removed from the live repo and excluded here so it does not come back.
Found by an audit pass, not by anything going wrong — which is the argument for
running them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Our own repo, not a submission to f-droid.org — and the difference is not
cosmetic. f-droid.org rebuilds from source and signs with their key, so an app
already installed under our signature could not be upgraded by it; Android
refuses a differently-signed APK over an existing install. This repo indexes
the APK we already signed, so everybody who sideloaded from the website
upgrades cleanly and then gets updates automatically.
The working directory holds a signing keystore and its password and lives
outside every checkout, because all four repos are public. The script refuses
to run if the keystore is missing rather than re-initialising over a live repo
— replacing the index key makes every client that has added the repository
reject its updates.
Version comes out of the APK via aapt2 rather than being typed, same rule as
the update manifest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>