Skip to content

Security: Villoh/morphe-builder

Security

docs/security.md

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:

A4FBBB098E4A9F23C45BFA34A85EBC2B6FF7BC24BD745331B2DA5DD89B448942

Because 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.toml

A 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.

There aren't any published security advisories