Skip to content

security: remove hardcoded keystore passwords, disable backup, harden WebView - #1

Draft
evnchn wants to merge 1 commit into
masterfrom
security/audit-fixes
Draft

evnchn wants to merge 1 commit into
masterfrom
security/audit-fixes

Conversation

@evnchn

@evnchn evnchn commented Aug 13, 2026

Copy link
Copy Markdown

Summary

Security audit fixes for three issues found during code review. Further findings (cleartext traffic policy, unencrypted WebSocket, EncryptedSharedPreferences) require product decisions and are tracked separately.

Changes

1. Remove hardcoded keystore passwords from build.gradleCRITICAL

The release signing config had storePassword "chromeclone123" and keyPassword "chromeclone123" committed in plaintext. While the .keystore file itself was gitignored, the passwords were not — anyone with read access to the repo could sign release APKs with the same key.

Fix: Passwords are now read from Gradle project properties (CHROMECLONE_STORE_PASSWORD, CHROMECLONE_KEY_PASSWORD), which should be set in local.properties (already gitignored) or via -P on the command line.

2. Disable ADB backup — HIGH

android:allowBackup="true" allowed extraction of all app data (SharedPreferences containing server URLs, bookmarks, capture config) via adb backup.

Fix: Set android:allowBackup="false".

3. Harden WebView file-access settings — MEDIUM

setAllowFileAccess(true) is needed for file:///android_asset/ pages, but on pre-API-30 devices (minSdk is 26) setAllowFileAccessFromFileURLs and setAllowUniversalAccessFromFileURLs default to true, allowing file:// pages to read other local files and make cross-origin requests.

Fix: Explicitly set both to false.

Migration note

After merging, each developer must add to their local.properties:

CHROMECLONE_STORE_PASSWORD=chromeclone123
CHROMECLONE_KEY_PASSWORD=chromeclone123

Remaining items (need product decisions)

  • usesCleartextTraffic="true" + MIXED_CONTENT_ALWAYS_ALLOW (browser needs HTTP but should scope it)
  • Unencrypted ws:// WebSocket to VLM service (screen/camera frames in plaintext on LAN)
  • SharedPreferences for server URL → consider EncryptedSharedPreferences
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission scope

… WebView

- Move keystore storePassword/keyPassword out of build.gradle (committed
  in plaintext) into local.properties via Gradle project properties.
  The keystore file itself was already gitignored but the passwords were
  not — anyone with repo access could sign release APKs.
- Set android:allowBackup="false" to prevent ADB backup extraction of
  SharedPreferences (server URLs, bookmarks, capture config).
- Explicitly disable setAllowFileAccessFromFileURLs and
  setAllowUniversalAccessFromFileURLs for pre-API-30 devices (minSdk 26).
evnchn added a commit that referenced this pull request Aug 14, 2026
`./gradlew build` runs validateSigningRelease, which requires
app/chromeclone.keystore. That file is gitignored and generated
per-checkout, so it never exists on a runner — every run failed with
`Execution failed for task ':app:validateSigningRelease'`.

Build assembleDebug / testDebugUnitTest / lintDebug instead. Debug does
not touch the release signing config, so CI also stays green once the
keystore credentials move out of build.gradle into local.properties
(PR #1) — which a runner will not have either.

Also:
- Drop the redundant `test` and `lint` steps (`build` already ran both).
- if-no-files-found: error on the APK upload, so a missing artifact
  fails loudly instead of passing silently.
- Add concurrency guard, timeout-minutes, permissions: read and
  workflow_dispatch.
- Upload the lint report for triage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant