security-assessment-2026-09-01-plan.md
Implementation Plan: 2026-09-01 Security Assessment Remediation
Overview
Resolve every open finding in docs/peach-android-independent-security-assessment-2026-09-01.pdf
against the current v2.14.89 tree. Work is ordered by release risk, delivered as small Koh saves,
and kept separate from the deferred PIN hardware-validation queue.
Architecture Decisions
- Treat
local.propertiesas SDK configuration only. Release signing secrets must arrive through protected environment injection, and release builds fail closed when the required inputs are absent. - Permit external URL dispatch only for canonical HTTPS URLs. Bare hosts normalize to HTTPS; HTTP and all non-web schemes are rejected.
- Authenticate update metadata before trusting any manifest field, using a pinned offline verification key and a versioned signed envelope. Existing APK checksum, identity, version, and signer-lineage gates remain.
- Keep release logging to opaque, redacted event identifiers. Debug builds may retain diagnostic detail.
- Preserve favicon opt-in but require informed consent naming the provider and disclosure scope; validate domains and cache containment inside the favicon helper itself.
- Pin the Rust toolchain and verify the native build provenance without introducing a new dependency.
Task List
Phase 1: Release-root blockers
- [ ] PB-26-025: remove plaintext signing secrets and investigate exposure/rotation.
- [ ] PB-26-026: enable and validate R8 plus resource shrinking.
- [ ] PB-26-027: restrict external URL opening to canonical HTTPS.
Checkpoint: Release blockers
- [ ] Fresh-workspace release signing uses protected injection only.
- [ ] Shrunk release builds and critical device flows pass.
- [ ] Hostile and non-HTTPS URI tests pass.
Phase 2: Integrity and privacy boundaries
- [ ] PB-26-028: require independently signed update metadata.
- [ ] PB-26-029: remove debug credential literals from production source/package.
- [ ] PB-26-030: add informed favicon consent and opt-out network proof.
- [ ] PB-26-031: enforce redacted release logging.
Checkpoint: Integrity and privacy
- [ ] Forged, stale, rollback, alternate-URL, and key-rotation update cases are covered.
- [ ] Release APK contains no demo credential literals.
- [ ] Opt-out produces no favicon requests; opt-in copy names DuckDuckGo and inventory disclosure.
- [ ] Malformed sync/pairing inputs emit only approved opaque release events.
Phase 3: Supply-chain and helper hardening
- [ ] PB-26-032: pin Rust and native build provenance.
- [ ] PB-26-033: validate favicon hosts and canonicalize cache paths at the helper boundary.
Checkpoint: Complete
- [ ] Full JVM tests, lint, release build, and applicable instrumentation/smoke gates pass.
- [ ] Release artifacts are inspected for shrinking, credential literals, signer identity, and native provenance.
- [ ] Every finding has a resolution record, Koh save, validation evidence, and residual-risk statement.
- [ ] The original PIN hardware-validation queue remains unchanged for follow-up.
Finding Resolution Details
PB-26-025 - Signing credentials
Acceptance criteria: no signing password or keystore path is read from local.properties; local-only
configuration is ignored; missing protected inputs cannot silently produce a publishable release; a sanitized
history/workspace search is recorded. Rotation, revocation, backup/CI review, and old-signer disposition are
owner actions and must not be falsely marked complete from source changes alone.
Verification: configuration tests or Gradle task checks cover missing/present injection; koh diff contains
no secret value; a fresh-workspace release build path is documented and exercised where credentials are available.
Likely files: .gitignore or Koh ignore configuration, app/build.gradle, release documentation.
PB-26-026 - Release shrinking
Acceptance criteria: release enables minifyEnabled and shrinkResources; narrow project keep rules exist;
security-sensitive reflection/serialization paths continue working.
Verification: unit, lint, release, APK inspection, and device smoke tests for unlock, autofill, passkeys, updates, crypto/import, and sync/pairing.
Likely files: app/build.gradle, app/proguard-rules.pro, focused tests/documentation.
PB-26-027 - External URL allowlist
Acceptance criteria: bare valid hosts and HTTPS normalize safely; HTTP, intent:, file:, custom schemes,
malformed authorities, credentials, control characters, and encoded separator attacks do not reach ACTION_VIEW.
Verification: focused pure unit tests first, then compile and a manual open-link smoke test.
Likely files: AdditionalUrlsDetail.kt, a focused JVM test.
PB-26-028 - Signed update metadata
Acceptance criteria: a versioned signature covers the exact trusted manifest bytes; verification uses a pinned public key before parsing URLs/checksums/notes; unknown keys, invalid signatures, stale metadata, and rollback fail closed.
Verification: deterministic signature vectors plus forged HTTPS, key transition, alternate URL, stale, and rollback tests.
Dependencies: release-side offline signing key and manifest signing step must be available before completion. The current local architecture spans three repositories: Koh publishes the artifacts, Kepr persists and serves the release record, and Peach verifies it. Koh's updater already defines a per-platform Ed25519 envelope shape, but the build/offer path does not produce those signatures and Kepr's generic endpoint does not persist or emit them. Reuse that shape only after defining one canonical byte payload and a production key-custody boundary. The public Kepr service must not hold the offline private key.
Likely files: UpdateRepository.kt, manifest model/tests, Kepr build/release scripts and documentation.
PB-26-029 - Debug seed isolation
Acceptance criteria: predictable usernames, passwords, and TOTP seeds leave production source; debug QA data is generated at runtime or isolated under debug/test sources; release artifact string/symbol inspection is clean.
Verification: debug seed behavior test plus release APK scan.
Likely files: VaultListViewModel.kt, debug source-set helper, focused tests.
PB-26-030 - Favicon consent
Acceptance criteria: enabling site icons requires explicit copy naming DuckDuckGo and explaining one request per distinct vault domain; declining or disabling causes no network requests; prior opt-ins are re-consented after the copy change.
Verification: settings-state tests, UI test where practical, and network-capture/fake-client proof of zero opt-out requests.
Likely files: settings model/UI, VaultListScreen.kt, favicon tests and privacy documentation.
PB-26-031 - Release logging
Acceptance criteria: production sync/pairing logs contain only allowlisted opaque event names and redacted error classes; payloads, peer identifiers, protocol material, raw exception messages, and stack traces are excluded.
Verification: logger unit tests and a release log capture under malformed inputs.
Likely files: sync logging helper and the three reported sync/adoption call sites.
PB-26-032 - Rust provenance
Acceptance criteria: Rust channel/version and target inputs are pinned; Cargo uses the lockfile; produced native artifacts have recorded source/toolchain/target hashes or equivalent reproducible provenance.
Verification: pinned-toolchain build and provenance output comparison.
Likely files: rust-toolchain.toml, root build.gradle, native build/release documentation.
PB-26-033 - Favicon cache containment
Acceptance criteria: helper accepts only canonical validated DNS hosts; every hit/miss cache path remains a direct child of the favicon cache directory; invalid caller material cannot create, read, or write another path.
Verification: traversal, separator, Unicode/control, malformed-host, and valid-IDN/domain unit tests.
Likely files: Favicons.kt, focused tests.
Risks and Mitigations
| Risk | Impact | Mitigation |
|---|---|---|
| Signing credentials may already exist outside this workspace | Source cleanup cannot revoke compromise | Keep release blocked until the owner completes rotation/exposure review |
| R8 removes reflected or JNI-reached code | Runtime-only regression | Start with narrow rules, inspect mapping/usage, and run device smoke gates |
| Signed metadata requires release-channel coordination | Client-only change could block all updates | Land signer tooling and client verification as one coordinated, rollback-tested unit |
| Re-consent reduces favicon adoption | Expected privacy tradeoff | Use concise, explicit copy and preserve initials fallback |
| Log reduction hurts diagnostics | Production failures become harder to investigate | Retain opaque event IDs and detailed debug-only logs |
Open Questions
- The release-signing values' exposure beyond this machine, rotation capability, and old-signer disposition are UNCONFIRMED.
- The offline update-metadata signing key custodian and Kepr manifest-signing integration are UNCONFIRMED.
- Physical-device availability for the R8 and release-log smoke matrices is UNCONFIRMED.