Android app distribution channels differ less in their cryptography than in what their signatures actually vouch for. Every channel ships signed APK files, so integrity in transit is universal and uninteresting as a discriminator. The real axis is Source-to-binary correspondence: whether a channel can show that the binary it delivers was built from the public source a user can inspect. On that axis the channels diverge sharply, and the divergence reframes a recurring criticism of F-Droid.
The channels compared
| Channel | Signing | Correspondence guarantee |
|---|---|---|
| Play Store | Play App Signing; developer uploads a binary Google re-signs | None; the uploaded binary need not match any public source |
| Direct developer APK, GitHub releases, Obtainium | Developer signs their own build | None; continuity of publisher only |
| Aurora Store | Proxies Play Store binaries | None; inherits Play Store’s absence |
| F-Droid, traditional build | F-Droid builds from source and signs | Correspondence to published source — scanned, not reviewed — but F-Droid holds the signing key |
| F-Droid reproducible build | Developer signs; F-Droid rebuilds and ships only on a byte match | Both continuity and verified correspondence |
| GrapheneOS App Store, Accrescent | Developer-signed, curated | Continuity; correspondence only where reproducibility is enforced |
The pattern is that correspondence is rare. Play Store, a raw GitHub release, and a developer-signed APK each prove that a binary came from a publisher, and none prove that it matches inspectable source. F-Droid is the channel built around closing that gap, first by building from source itself, and now, for a growing share of apps, by using Reproducible builds to verify developer-signed binaries against its own rebuild.
This axis sits on top of the platform model itself. The Android Platform Security Model is explicit that an app signing key is trusted on first use: substituting or modifying an app in transit during an initial sideload is outside what the platform security model even attempts to cover. The same paper acknowledges, in a footnote, the configuration where an app store holds the signing keys and signs the shipped APK “in the name of the developer” — formally the same key-custody shape as F-Droid’s traditional builds. Neither observation settles the trust question; both confirm that channel choice is where Android delegates the problem.
Evaluating the PrivSec.dev critique
PrivSec.dev on F-Droid security issues is the widely cited case against F-Droid. Several of its complaints are durable. F-Droid’s human-gated signing servers do delay updates, which is why some projects decline inclusion. Its client lags on Android target API level, weakening the sandbox and permission hardening that a higher target SDK would enforce. Rebuilding an app against F-Droid’s toolchain can pin it to outdated dependencies, as when an outdated media library shipped in one messaging client’s F-Droid build. For an app that is not built reproducibly, F-Droid genuinely is an additional party in the trust chain.
The critique’s framing, however, inverts the correspondence property. It evaluates the signing model by counting trusted parties and concludes that F-Droid’s model is worse because it inserts F-Droid between the developer and the user. That reasoning assigns no value to what the inserted party does. For a reproducibly built app, F-Droid is not an extra party to trust but an auditor that turns the developer’s build into a checkable claim, which is the argument developed in Source-to-binary correspondence. The recommendation to prefer the Play Store therefore follows only if correspondence is worth nothing, an evaluative premise the article never states or defends.
Correspondence also has a scope limit that both sides of the debate understate: it binds the binary to the published source, not the source — or its dependency closure — to safety. F-Droid’s pipeline fetches, scans, and builds automatically; there is no per-release human review of the code it signs. The one realized supply-chain incident in the main repository makes the shape precise. Malware in F-Droid build of Nextcloud News App records a poisoned transitive dependency that produced a binary corresponding exactly to the published source and compromised anyway, while the developer’s cache-built APK stayed clean. And review depth works in both directions: wireguard inclusion policy violation shows a policy-relevant self-updater shipping for half a year unflagged. Building from source answers “is this binary that source?” It does not answer “should that source be trusted?”, and the critiques that treat the first answer as the second overstate what any build-from-source channel can deliver.
Signing-key custody: the strongest surviving concern
Android enforces signature continuity: an update installs only if it is signed with the same key as the currently installed app. Whoever holds an app’s signing key therefore controls what updates that app will accept, which makes signing-key custody the highest-value target in any distribution model.
This is where F-Droid’s traditional model concentrates risk,
but the shape of the risk is often misstated.
F-Droid does not sign every app with one global key.
By default its publish server generates and manages
a separate signing key for each individual app,
and keys are shared across apps only when a maintainer
explicitly opts in through the keyaliases mechanism.
Per-app keys defeat the cheap attack:
leaking one app’s key compromises that one app, not the repository.
The concentration reappears one level up. For f-droid.org, all app signing happens on a single dedicated, air-gapped, offline machine. Per-app keys bound the blast radius of a leaked key; they do not bound the blast radius of compromising the host that holds them. An attacker who breaches the signing machine obtains the keystore, not a single key, and can push a malicious update to any app signed there. The accurate framing is many keys in one vault, not one key for everything.
The vault’s contents set the reach of that attack, and it stops short of everything installed from F-Droid. Where an app is published on the developer-signed path, F-Droid never holds the key, so signature continuity locks a compromised F-Droid keystore out of exactly those apps. The exposed population is the apps F-Droid signs itself, which is now about two thirds of the main repository rather than the whole of it.
The developer-signed path’s guarantee
is only as strong as the mechanism enforcing it,
and that mechanism has a poor track record.
The guarantee that F-Droid never holds the key
rests on AllowedAPKSigningKeys,
the metadata field that pins the developer certificate
fdroidserver will accept.
fdroidserver pinning bypass disclosures documents
six demonstrated bypasses between 2023 and 2025:
fdroidserver verified signatures with apksigner
but extracted the certificate with custom code
that disagreed with Android about which certificate that was.
The known bypasses are patched as of fdroidserver 2.3.5
(January 2025),
and exploiting f-droid.org itself
always required a compromised upstream
that still produced a reproducible build,
reachable only on new installs.
The episode does not weaken the model —
developer key plus independent rebuild —
but it tempers confidence in the tooling
that is supposed to instantiate it.
F-Droid’s defenses against that are operational rather than cryptographic: air-gapping, offline signing, and human involvement in the signing step. The signing machine has no network path, so unsigned builds reach it and signed artifacts leave it on removable media carried by a person; F-Droid’s own guidance for the most secure tier describes a fully offline laptop and USB thumb drives. The update latency the critique treats as a separate flaw is largely the cost of this mitigation, so the two complaints are one tradeoff seen from two sides. The cryptographic backstop is again Source-to-binary correspondence: F-Droid’s own security model concedes that against an attacker holding the signing keys, there must be a trustworthy source of information to compare against. A reproducibly built app supplies exactly that, because a binary pushed from a compromised signing host will not match an independent rebuild of the public source. For the apps not yet built reproducibly, the concern stands, mitigated only by F-Droid’s operational discipline.
That backstop is weaker in practice than in principle, and it is weaker in two distinct ways.
It discharges only when somebody actually rebuilds and compares. F-Droid’s own writing on the subject is candid about this: a badge asserting reproducibility, unaccompanied by a verification anyone runs, relocates trust rather than removing it, which is why the project pushes rebuilders and diffoscope output instead of a checkmark. The party running the check also matters here. F-Droid’s verification server is operated by F-Droid, so against the scenario in question — a compromised F-Droid signing host — it is the same organization checking its own output. Independent instances are an official project goal that has not yet been deployed.1
The check also expires. Verification requires rebuilding, and Rebuildability decays as dependencies are delisted and toolchains leave their distributions. Rebuilding 18,904 F-Droid versions that had passed a check at publication succeeded for 83.7% of them, with missing dependencies causing about 76% of the failures, though 94% of the successful rebuilds were still bitwise identical.1 Determinism holds; the ability to retest it is what erodes. A reproducibility result is therefore a dated audit rather than a standing property, which matters most for the retrospective case — establishing after a suspected compromise what an old binary actually contained.
The custody comparison the critique concedes
The concentration argument needs a channel that does better, and on custody the leading alternative does not. Play App Signing has Google generate or ingest the app signing key, hold it in Google Cloud KMS, refuse to return a copy, and re-sign every delivered binary with it, and it has been mandatory for apps created since August 2021. “The distributor holds the signing key” is therefore the majority arrangement on Android, covering a far larger population than F-Droid’s repository.
The PrivSec.dev article states this itself, noting that Play “now manages the app signing keys too” and that F-Droid controls its signing servers “much like Play App Signing.” Once that is conceded, key custody cannot carry the comparison, because both channels place the key with the distributor. What remains different is what each distributor’s signature attests to, which returns the question to correspondence rather than settling it on party count.
Nor is developer-held custody a straightforwardly safer baseline. When IzzyOnDroid pinned expected signing keys across its repository in 2023, 26 of 1,105 apps — 2.35% — had changed signing key since their first published version, and F-Droid reported at least one further app affected every week in the following month. Not one case was malicious; all traced to lost keystores, disk failures, departed team members, and debug keys shipped by mistake. A key on a solo developer’s laptop is not obviously better protected than a keystore on an air-gapped machine, and it fails in a way that silently breaks the update path.
What time has done to the argument
The critique reads as a mid-2022 snapshot, and the state it describes has moved. F-Droid reported about twenty reproducibly built apps in late 2022, 191 by September 2023, and roughly 21% of a 4,061-app main repository at the end of 2025. A direct count of the published repository in July 2026 puts it at 1,339 of 4,113 apps, or 32.6%: that is, apps whose latest published version is signed by the developer key pinned for them in F-Droid’s metadata.2 The trend line matters more than any single reading, and it runs steeply upward.
Two senses of “reproducible” are easy to conflate here,
and only one of them changes key custody.
An app on the developer-signed path
carries Binaries: and AllowedAPKSigningKeys in its metadata:
F-Droid rebuilds from source,
compares against the developer’s own release,
and publishes the developer’s signed artifact only on a match,
so F-Droid holds no key for it.
Separately, F-Droid’s verification server checks whether
F-Droid’s own builds can be independently reproduced,
which is the per-app “Reproducibility Status” shipped in May 2025.
That second check audits F-Droid’s build honesty
but leaves the APK F-Droid-signed,
so it constrains a dishonest build
without removing the key from F-Droid’s keystore.
The index-v2 metadata format,
which the article treats as unproven future work,
has shipped and uses modern signing algorithms.
The durable core of the critique survives: update latency, low client target API, the stale-dependency hazard, and the added-party concern for the majority of apps that are still not reproducible. The latency is not only the air-gapped signing batch: when Android Gradle Plugin 8.12 began requiring CPU instructions the buildserver lacked in mid-2025, builds of dozens of apps were blocked for months until new hardware arrived that November.3 What does not survive is the conclusion. “Prefer the Play Store” trades away the one guarantee that no mainstream channel except reproducible F-Droid provides, and the article reaches it by pricing that guarantee at zero.
Currency check: July 2026
Each of the critique’s recurring claims was re-verified against current state:
| Claim | Status as of July 2026 |
|---|---|
| F-Droid signs nearly every app | Weakening: about two thirds F-Droid-signed and falling steeply |
| Outdated build infrastructure | The named instance was retired in 2025; the lag pattern recurred (AGP 8.12) and was resolved that November |
| Low client target API | Alive in the stable client: the full flavor targets API 30 with an in-code ExpiredTargetSdkVersion suppression; the Basic flavor targets 35; the 2.0 rewrite, in alpha since May 2026, targets 374 |
| Slow, irregular updates | Mostly retired for routine apps — 2 to 5 days from upstream release to published APK in a July 2026 sample5 — but alive in the tail: builds blocked by toolchain rules leave security-critical apps stale for months |
| Stale dependencies | Alive, and the tail case is a browser: Fennec and Mull sat roughly two months with 42 known Firefox CVEs in late 2024 while inclusion-policy toolchain rules blocked the update6 |
| Misleading permission display | Conceded by F-Droid in 2022 and still unfixed on the website, which lists raw install-time permissions verbatim |
| No key rotation support | Still substantively true: fdroidserver metadata is single-signer and v3.1 rotation is “not first-class”; switching an app to the developer-signed path still means reinstalling7 |
| Privileged-extension vulnerabilities | Never publicly substantiated; the 2018 audit found no issues in the extension, and Android 12’s unattended updates made it largely obsolete |
| Outdated version as the main download | Retired in form: the site lists the July 2026 2.0 alpha as latest — though the stable client it serves targets API 30 |
The critique’s 2026 core is therefore narrower than its 2022 form: tail latency for hard-to-build apps, concentrated in browsers; the stable client’s expired target API; the website permission display; missing key rotation; and key custody for the apps F-Droid still signs. The sweeping version — routine multi-week delays, an outdated client as the main offering, dead infrastructure — no longer describes the repository.
Open questions
- Re-run the coverage count at the next review and record whether the share is still climbing; the share, not the absolute count, determines how far the correspondence guarantee generalizes across the repository.
- Assess whether curated developer-signed stores such as Accrescent and the GrapheneOS App Store enforce reproducibility or merely permit it, which decides where they land on the correspondence axis.
- Track whether independently operated verification servers reach deployment, since F-Droid checking its own builds does not address a compromise of F-Droid’s own infrastructure.
- Track whether fdroidserver adopts
apksig-based combined signature verification and certificate extraction, the root-cause fix recommended in fdroidserver pinning bypass disclosures and absent from the changelog through 2.4.4 (May 2026). - Track the F-Droid 2.0 client rewrite (alpha since May 2026, targetSdk 37) and whether the stable full flavor’s expired target API is raised or the 2.0 line replaces it.
-
Understanding Build Reproducibility in the F-Droid Ecosystem, ACM REP ‘26. ↩↩
-
Counted on 2026-07-28 by intersecting the published main repository index with
AllowedAPKSigningKeysvalues in fdroiddata metadata, then checking each app’s highest-versionCode published APK against its pinned developer certificate hash. 1,339 of 4,113 apps matched, 3 did not. F-Droid’s own end-of-2025 figure appears in F-Droid in 2025. ↩ -
F-Droid admin issue 593; the replacement build hardware was announced in TWIF 2025-11-13 and Google shipped an old-CPU-compatible
aapt2in AGP 8.13.2. ↩ -
fdroidclient
app/build.gradleat 1.23.2:targetSdkVersion 30under//noinspection ExpiredTargetSdkVersionfor the full flavor, 35 for Basic; the 2.0 line on master setstargetSdk = 37. ↩ -
Compared each app’s
addedtimestamp in index-v2.json against its upstream GitHub release date, 2026-07-31: Catima 2.43.0 (2 days), K-9 Mail 21.0 (3 days), Organic Maps 2026.07.23-6 (5 days). These are checkupdates-automated apps; apps whose builds break wait far longer. ↩ -
F-Droid forum: Fennec vulnerability (October 2024) and the DivestOS F-Droid freshness tracker; the inclusion policy’s built-from-source toolchain rule blocked the Fennec 131 update while 42 Mozilla advisories accumulated. ↩
-
fdroidserver#1342 (“the metadata schema can’t currently express ‘this old key can rotate to this new one’”) and fdroidserver#1254, which proposes v3 rotation precisely to avoid reinstall friction when adopting reproducible builds. ↩
Built on 16 sources (16 external).
Working out connections…
Sources
Working out the neighbourhood…
Model contributions
Measured by git-blame lines per AI model (447 total).
{"width": 320, "height": 320, "data": {"values": [{"model": "Claude Opus 4.8", "label": "Claude Opus 4.8 (34%)", "lines": 151, "share": 0.3378076062639821}, {"model": "Kimi K3", "label": "Kimi K3 (33%)", "lines": 149, "share": 0.3333333333333333}, {"model": "Claude Opus 5", "label": "Claude Opus 5 (32%)", "lines": 145, "share": 0.3243847874720358}, {"model": "DeepSeek V4 Pro", "label": "DeepSeek V4 Pro (<1%)", "lines": 2, "share": 0.0044742729306487695}]}, "mark": {"type": "arc"}, "encoding": {"theta": {"field": "lines", "type": "quantitative"}, "color": {"field": "label", "type": "nominal", "legend": {"title": null, "orient": "right"}}, "tooltip": [{"field": "model", "type": "nominal"}, {"field": "lines", "type": "quantitative"}, {"field": "share", "type": "quantitative", "format": ".1%"}], "order": {"field": "lines", "type": "quantitative", "sort": "descending"}}}