Every finding from the audit, paired with a concrete fix, an effort estimate and an
owner. Most are pipeline/process hardening — separating dev and prod builds, tightening signing
and key restrictions — not rewrites. Closing the quick wins alone lifts the posture materially before
the next build. Items are ordered P1 → P4.
Remediation items
P1Non-production backend endpoint shipped in release build★ quick win
Surface: MASVS-CODE · MOB-001Effort: M (1–2 days)Owner: Mobile + CI/CD
A development/staging API base URL is embedded in the shipped, production-signed app. Dev backends are commonly weaker (verbose errors, looser auth, test data) and widen the attack surface against the firearm's command/cloud path.
Fix
Move the API base URL out of the source and inject it per build: a `--dart-define=API_BASE=…` (or Flutter flavors dev/staging/prod) so the release flavor can only ever compile the prod URL.
Add a release-gate step in CI that greps the built `libapp.so` / bundle and FAILS the build if any `-dev`/`staging`/`test` host is present.
Rotate or firewall the dev backend so it is not reachable from production app installs.
OWASP MASVS-CODE · MASTG-TEST build-config
P2App signed with a development identity★ quick win
Surface: MASVS-RESILIENCE · MOB-001Effort: S (2–4 h)Owner: Release engineering
The signing certificate names a Development/Debug identity rather than a guarded production release key — review the release signing process and key custody.
Fix
Create a dedicated **release keystore** held in secrets custody (not a developer's machine); enroll the app in **Google Play App Signing**.
Configure Gradle `signingConfigs.release` to use it and ensure `flutter build appbundle --release` never falls back to the debug/dev key.
Confirm `OU=Development` no longer appears in the release certificate.
OWASP MASVS-RESILIENCE · Android app signing
P2No Network Security Config
Surface: MASVS-NETWORK · MOB-001Effort: S (2–4 h)Owner: Mobile
No explicit network_security_config.xml. Cleartext is off by default for targetSdk≥28, but an explicit config (+ cert pinning) is recommended for a safety-critical app.
Fix
Add `res/xml/network_security_config.xml` with `cleartextTrafficPermitted="false"` and reference it from the manifest `application` tag.
Add **certificate pinning** to the LodeStar backend domain (pin the leaf or intermediate SPKI). For a safety-critical command path, pinning closes the rogue-CA / MITM gap.
Mirror the same posture on iOS via ATS (no arbitrary loads) + pinning.
OWASP MASVS-NETWORK · Android NSC / iOS ATS
P2Firebase API key embedded★ quick win
Surface: MASVS-CODE · MOB-001Effort: S (2–4 h)Owner: Backend / Firebase
A Firebase/Google API key is shipped in the app. This is normal for Firebase but MUST be locked down with API key restrictions + Firebase Security Rules, or it enables abuse of the project's backend.
Fix
In Google Cloud Console, add **Application restrictions** (Android app SHA-256 + package) and **API restrictions** (only the Firebase APIs actually used) to the API key.
Enable **Firebase App Check** so only attested app instances can call the backend.
Lock down **Firebase Security Rules** (Firestore/RTDB/Storage) — the embedded key is harmless only if the rules are.
OWASP MASVS-CODE · Firebase API key restrictions
P31 app-owned exported component(s)★ quick win
Surface: MASVS-PLATFORM · MOB-004Effort: XS (~30 min)Owner: Mobile
Exported components are reachable by other apps on the device. Confirm each validates its caller and cannot be coerced into a privileged action.
Fix
Audit each app-owned exported component. For `MainActivity`, keep `android:exported="true"` only for the launcher intent; set `false` on anything that does not need external reachability.
For any deep-link / custom-scheme intent-filter, validate and sanitise all incoming data before it can reach a privileged (BLE-command) code path.
Surface: MASVS-CODE · MOB-001Effort: XS (~30 min)Owner: Mobile / Observability
A Sentry DSN is embedded (expected for crash reporting); confirm it is ingestion-only and rate-limited so it cannot be abused.
Fix
Confirm the DSN is **ingestion-only** (public DSN cannot read issues) and enable per-key **rate limiting / spike protection** in Sentry.
Optional: route crash reports through a thin proxy if you want to hide the project id.
OWASP MASVS-CODE
P4Proprietary BLE GATT contract recovered (15 UUIDs)
Surface: MASVS-CODE · BLE-003Effort: — (—)Owner: Firmware + Mobile (design)
The app's custom BLE service/characteristic UUIDs were recovered from the binary. These are the LNK9 command channel — classify which characteristic commands the sear and gate it under the safety interlock when probing (BLE-003).
Fix
Not an app bug — a design checkpoint for the live BLE testing. Confirm the command characteristic requires **LE Secure Connections** (authenticated encryption), not Just-Works pairing.
Confirm the unlock/owner command is bound to a **per-device key** (not a shared/static secret reusable across guns) and includes anti-replay (nonce/counter).
This recovered UUID map drives the BLE-003 test — we will probe these characteristics under the firearm safety interlock.