1# Implementation Plan: 2026-09-01 Security Assessment Remediation23## Overview45Resolve every open finding in `docs/peach-android-independent-security-assessment-2026-09-01.pdf`6against the current v2.14.89 tree. Work is ordered by release risk, delivered as small Koh saves,7and kept separate from the deferred PIN hardware-validation queue.89## Architecture Decisions1011- Treat `local.properties` as SDK configuration only. Release signing secrets must arrive through12 protected environment injection, and release builds fail closed when the required inputs are absent.13- Permit external URL dispatch only for canonical HTTPS URLs. Bare hosts normalize to HTTPS; HTTP and14 all non-web schemes are rejected.15- Authenticate update metadata before trusting any manifest field, using a pinned offline verification16 key and a versioned signed envelope. Existing APK checksum, identity, version, and signer-lineage gates remain.17- Keep release logging to opaque, redacted event identifiers. Debug builds may retain diagnostic detail.18- Preserve favicon opt-in but require informed consent naming the provider and disclosure scope; validate19 domains and cache containment inside the favicon helper itself.20- Pin the Rust toolchain and verify the native build provenance without introducing a new dependency.2122## Task List2324### Phase 1: Release-root blockers2526- [ ] PB-26-025: remove plaintext signing secrets and investigate exposure/rotation.27- [ ] PB-26-026: enable and validate R8 plus resource shrinking.28- [ ] PB-26-027: restrict external URL opening to canonical HTTPS.2930### Checkpoint: Release blockers3132- [ ] Fresh-workspace release signing uses protected injection only.33- [ ] Shrunk release builds and critical device flows pass.34- [ ] Hostile and non-HTTPS URI tests pass.3536### Phase 2: Integrity and privacy boundaries3738- [ ] PB-26-028: require independently signed update metadata.39- [ ] PB-26-029: remove debug credential literals from production source/package.40- [ ] PB-26-030: add informed favicon consent and opt-out network proof.41- [ ] PB-26-031: enforce redacted release logging.4243### Checkpoint: Integrity and privacy4445- [ ] Forged, stale, rollback, alternate-URL, and key-rotation update cases are covered.46- [ ] Release APK contains no demo credential literals.47- [ ] Opt-out produces no favicon requests; opt-in copy names DuckDuckGo and inventory disclosure.48- [ ] Malformed sync/pairing inputs emit only approved opaque release events.4950### Phase 3: Supply-chain and helper hardening5152- [ ] PB-26-032: pin Rust and native build provenance.53- [ ] PB-26-033: validate favicon hosts and canonicalize cache paths at the helper boundary.5455### Checkpoint: Complete5657- [ ] Full JVM tests, lint, release build, and applicable instrumentation/smoke gates pass.58- [ ] Release artifacts are inspected for shrinking, credential literals, signer identity, and native provenance.59- [ ] Every finding has a resolution record, Koh save, validation evidence, and residual-risk statement.60- [ ] The original PIN hardware-validation queue remains unchanged for follow-up.6162## Finding Resolution Details6364### PB-26-025 - Signing credentials6566**Acceptance criteria:** no signing password or keystore path is read from `local.properties`; local-only67configuration is ignored; missing protected inputs cannot silently produce a publishable release; a sanitized68history/workspace search is recorded. Rotation, revocation, backup/CI review, and old-signer disposition are69owner actions and must not be falsely marked complete from source changes alone.7071**Verification:** configuration tests or Gradle task checks cover missing/present injection; `koh diff` contains72no secret value; a fresh-workspace release build path is documented and exercised where credentials are available.7374**Likely files:** `.gitignore` or Koh ignore configuration, `app/build.gradle`, release documentation.7576### PB-26-026 - Release shrinking7778**Acceptance criteria:** release enables `minifyEnabled` and `shrinkResources`; narrow project keep rules exist;79security-sensitive reflection/serialization paths continue working.8081**Verification:** unit, lint, release, APK inspection, and device smoke tests for unlock, autofill, passkeys,82updates, crypto/import, and sync/pairing.8384**Likely files:** `app/build.gradle`, `app/proguard-rules.pro`, focused tests/documentation.8586### PB-26-027 - External URL allowlist8788**Acceptance criteria:** bare valid hosts and HTTPS normalize safely; HTTP, `intent:`, `file:`, custom schemes,89malformed authorities, credentials, control characters, and encoded separator attacks do not reach ACTION_VIEW.9091**Verification:** focused pure unit tests first, then compile and a manual open-link smoke test.9293**Likely files:** `AdditionalUrlsDetail.kt`, a focused JVM test.9495### PB-26-028 - Signed update metadata9697**Acceptance criteria:** a versioned signature covers the exact trusted manifest bytes; verification uses a pinned98public key before parsing URLs/checksums/notes; unknown keys, invalid signatures, stale metadata, and rollback fail closed.99100**Verification:** deterministic signature vectors plus forged HTTPS, key transition, alternate URL, stale, and rollback tests.101102**Dependencies:** release-side offline signing key and manifest signing step must be available before completion.103The current local architecture spans three repositories: Koh publishes the artifacts, Kepr persists and serves104the release record, and Peach verifies it. Koh's updater already defines a per-platform Ed25519 envelope shape,105but the build/offer path does not produce those signatures and Kepr's generic endpoint does not persist or emit106them. Reuse that shape only after defining one canonical byte payload and a production key-custody boundary.107The public Kepr service must not hold the offline private key.108109**Likely files:** `UpdateRepository.kt`, manifest model/tests, Kepr build/release scripts and documentation.110111### PB-26-029 - Debug seed isolation112113**Acceptance criteria:** predictable usernames, passwords, and TOTP seeds leave production source; debug QA data114is generated at runtime or isolated under debug/test sources; release artifact string/symbol inspection is clean.115116**Verification:** debug seed behavior test plus release APK scan.117118**Likely files:** `VaultListViewModel.kt`, debug source-set helper, focused tests.119120### PB-26-030 - Favicon consent121122**Acceptance criteria:** enabling site icons requires explicit copy naming DuckDuckGo and explaining one request123per distinct vault domain; declining or disabling causes no network requests; prior opt-ins are re-consented after the copy change.124125**Verification:** settings-state tests, UI test where practical, and network-capture/fake-client proof of zero opt-out requests.126127**Likely files:** settings model/UI, `VaultListScreen.kt`, favicon tests and privacy documentation.128129### PB-26-031 - Release logging130131**Acceptance criteria:** production sync/pairing logs contain only allowlisted opaque event names and redacted132error classes; payloads, peer identifiers, protocol material, raw exception messages, and stack traces are excluded.133134**Verification:** logger unit tests and a release log capture under malformed inputs.135136**Likely files:** sync logging helper and the three reported sync/adoption call sites.137138### PB-26-032 - Rust provenance139140**Acceptance criteria:** Rust channel/version and target inputs are pinned; Cargo uses the lockfile; produced native141artifacts have recorded source/toolchain/target hashes or equivalent reproducible provenance.142143**Verification:** pinned-toolchain build and provenance output comparison.144145**Likely files:** `rust-toolchain.toml`, root `build.gradle`, native build/release documentation.146147### PB-26-033 - Favicon cache containment148149**Acceptance criteria:** helper accepts only canonical validated DNS hosts; every hit/miss cache path remains a direct150child of the favicon cache directory; invalid caller material cannot create, read, or write another path.151152**Verification:** traversal, separator, Unicode/control, malformed-host, and valid-IDN/domain unit tests.153154**Likely files:** `Favicons.kt`, focused tests.155156## Risks and Mitigations157158| Risk | Impact | Mitigation |159|---|---|---|160| Signing credentials may already exist outside this workspace | Source cleanup cannot revoke compromise | Keep release blocked until the owner completes rotation/exposure review |161| R8 removes reflected or JNI-reached code | Runtime-only regression | Start with narrow rules, inspect mapping/usage, and run device smoke gates |162| 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 |163| Re-consent reduces favicon adoption | Expected privacy tradeoff | Use concise, explicit copy and preserve initials fallback |164| Log reduction hurts diagnostics | Production failures become harder to investigate | Retain opaque event IDs and detailed debug-only logs |165166## Open Questions167168- The release-signing values' exposure beyond this machine, rotation capability, and old-signer disposition are UNCONFIRMED.169- The offline update-metadata signing key custodian and Kepr manifest-signing integration are UNCONFIRMED.170- Physical-device availability for the R8 and release-log smoke matrices is UNCONFIRMED.