Security
This project downloads untrusted binaries from the internet, runs third-party tools on them, signs the result, and publishes it. This document states what is defended, what is deliberately not, and where the real trust boundaries are.
Threat model
| Boundary | Main threats | Controls |
|---|---|---|
| Google Play downloader | stolen tokens, malformed metadata, partial or substituted APKs | external goopdl process pinned by commit; redacted errors; size, digest, manifest, and signature verification; atomic publication |
| Fallback providers | hostile URLs, mirror metadata, oversized files, downgrade attempts | HTTPS host and path validation, bounded retries/timeouts/sizes, mirror metadata treated as untrusted, full APK verification before publication |
| Tool and patch downloads | release substitution, ambiguous assets, concurrent cache corruption | GitHub release validation, exact asset selection, upstream checksum when available, local SHA-256 provenance, bounded downloads, exclusive cache locks |
| APK and module archives | traversal, symlinks, zip bombs, malformed manifests | no archive extraction; safe entry names, entry-count, uncompressed-size, and compression-ratio limits enforced before archive reads |
| Keystore | signer impersonation, key loss, incompatible future updates | documented public template key for ready-to-run forks; optional private override; passwords outside argv and logs; certificate fingerprint in provenance |
| Subprocesses | shell injection, secret-bearing argv, hangs | argument arrays with shell=False, explicit timeouts, sanitized output, passwords through environment or stdin |
| CI and releases | secret exfiltration, poisoned caches, partial publication | secret-free default workflow, public-tool-only cache, pinned actions, pre-upload hash verification, draft release rollback, attestations |
Explicit non-goals
Being honest about what is not protected matters more than the control list:
- The public template key proves nothing about identity. Anyone can sign an APK with it. It provides update compatibility across forks, not publisher authenticity.
- Unpinned apps trust the provider's signer. Without
expected-signer, a valid and internally consistent signer is accepted and logged, not verified against a known-good value. - Patch behavior is not audited. The builder verifies that the Morphe CLI and patch bundle are the exact releases it recorded. It does not analyze what those patches do to the app.
- Mirror content is not attested. APKMirror and Uptodown downloads are verified against the requested identity and a valid signer, which does not make the mirror trustworthy, only its output checkable.
- Module runtime behavior is not proven by the build. Static generation cannot establish mount or root-manager behavior; see
modules.md.
Limits and concurrency
| Limit | Value |
|---|---|
| Network timeouts | 30 to 60 seconds, explicit per call |
| Download retries | 3 maximum |
| Provider file size | 300 MiB |
| Provider files per result | 20 |
| GitHub asset size | bounded by release-reported size |
| ZIP entries | 100,000 maximum |
| ZIP uncompressed size | 2 GiB maximum |
| ZIP compression ratio | 1000:1 maximum |
Symlinks and traversal paths in archives are rejected outright.
Tool cache writes use exclusive lock files and atomic replacement. A crashed process may leave a stale lock; remove it only after confirming no Morphe Builder process is still using that cache.
Supported platforms
| Role | Support |
|---|---|
| Builder host | Windows 10/11 and current Ubuntu Linux on x86-64, Python 3.11–3.13, Java 21+ |
| CI | Ubuntu GitHub-hosted runner, Python 3.11–3.13, Java 21 |
| Outputs | Android ARM64 and ARMv7 |
| Not validated | macOS and non-x86 builder hosts |
Device, Magisk, and KernelSU compatibility still requires the final validation matrix.
Keystore policy
The default workflow key .github/template-release.p12 is intentionally public. Alias and password are both morphe-builder, and its certificate SHA-256 is:
A4FBBB098E4A9F23C45BFA34A85EBC2B6FF7BC24BD745331B2DA5DD89B448942Because anyone can sign with it, it gives cross-fork update compatibility and no publisher identity. Trust a release only when GitHub provenance identifies the expected repository and workflow.
Maintainers who need an independent signing identity configure a private replacement through workflow secrets.
Warning: keep a replacement keystore and its password in separate encrypted backups. Losing the key makes future releases signature-incompatible, which forces users to uninstall the app and lose its data. Rotation requires a deliberate package and signing migration, and must never silently replace an existing release key.
Google Play and historical versions
Anonymous dispenser capacity is rate-limited and can return HTTP 429, and it is frequently blocked from datacenter ranges entirely. Configure account credentials for reliable access; see releases.md.
Auth tokens, caches, cookies, dispenser responses, and authenticated URLs must stay outside the repository and outside CI caches.
Google cohorts can present the same requested version code with different display metadata. The trusted APK manifest remains the authority, not store metadata.
For versions Google no longer serves, resolution order is: confirmed local mapping cache, then an APKMirror candidate version code used for a Google download, then a verified fallback download. Version codes are never derived arithmetically and candidate ranges are never brute-forced.
Integrity and signature failures are terminal. Only provider or version unavailability advances the fallback chain; see providers.md.
Clean-machine validation
On a fresh Windows or Ubuntu host with Git, uv, and Java 21:
uv sync --locked
uv run python -m unittest discover -s tests
uv lock --check
uv run morphe-builder tools
uv run morphe-builder list-patches morphe.tomlA live build uses the public goopdl dispenser and the committed template keystore by default. Account credentials, a custom dispenser, and a private replacement keystore are all optional. Final YouTube and YouTube Music ARM64/ARMv7 device or emulator validation is still required before declaring stable releases.
Public repository review
The repository and its forks may be public. Never commit downloaded APKs, private replacement keystores, auth material, or live screenshots. The documented template keystore is the sole intentional exception, because it is public signing material rather than a secret.
Repository-wide rules, including the never-commit list: rules/README.md.
