3.9 KiB
3.9 KiB
FuelBoard Security Audit
Audit date: 2026-08-11 · Scope: app, widget, relay, build pipeline, git history.
Summary
No critical issues. No secrets in source, git history, or binaries. The prior LAN relay/private-IP app path has been removed from the app binary; production data access is public HTTPS GitHub mirror plus bundled fallback. Findings below are ordered by severity.
Findings
1. LAN IP baked into app binary — RESOLVED
- The app no longer contains
RelayFuelProvider,fuelboard.relayFallback,NSLocalNetworkUsageDescription, or a private192.168.*live-data endpoint. - Live data uses the public HTTPS GitHub mirror; the app falls back to bundled data/cache when the mirror is unavailable.
- A built-binary
stringsscan should remain part of every release gate to ensure no private LAN endpoint is reintroduced.
2. No secrets in source / git / binary — PASS
- App + widget sources: no API keys, tokens, or passwords (only keychain
API usage in
FuelStore.swiftand OAuth documentation comments inFuelPriceProvider.swift). - Relay:
CLIENT_ID/CLIENT_SECRETread from environment only (app/main.py:31-32);.envis gitignored;__pycache__/*.pycuntracked;.env.exampleships empty placeholders. - Binary scan should show no private LAN data endpoint; expected network strings
include public GitHub raw URLs,
maps.apple.com, andgroup.com.apt.fuelboard. No credentials.
3. Price data hardening — PASS (three layers)
- Relay rejects out-of-band rows at the edge (
_fuel_price50–500 pence/litre). - App drops out-of-band grades at decode (
FuelPriceProvider.decodeStations, previouslyc1edd4d). - Station names title-cased at decode + on cache load (
aee890e). - Covered by unit tests (
FuelBoardTests—PriceGuardTests).
4. Keychain / app-group hygiene — PASS
- Keychain access groups:
com.apt.fuelboard.sharedlisted FIRST (default access group), thencom.apt.fuelboard— matches the proven WidgetBoard pattern for free-account keychain sharing. - Stations stored in app-group UserDefaults only (~2.9 MB exceeds keychain
limits; documented in
FuelStore.swift). Stored data is public price data — not sensitive. kSecAttrAccessibleAfterFirstUnlock— widget can read after reboot without unlock. Correct for background widget refresh.
5. Transport security — PASS
- No
NSAllowsArbitraryLoadsanywhere (confirmed by plist + pbxproj grep). - No cleartext LAN relay endpoint ships in the app binary. Live network data is fetched over HTTPS from the public GitHub mirror.
6. Privacy / permissions — review for App Store
NSLocationWhenInUseUsageDescription+NSLocationAlwaysAndWhenInUseUsageDescriptionboth present with clear copy. The app deliberately does not include thelocationvalue inUIBackgroundModes; optional alerts use CoreLocation region monitoring/significant-change behaviour rather than persistent real-time background tracking.- Location is the only sensitive permission requested. No contacts, photos, camera, mic.
- No third-party SDKs → no SDK privacy manifests required.
What was checked
- Source secret scan (app, widget, shared, relay, config)
- Git history scan (all 43 commits, both repos)
- Built binary string scan (app + widget)
- Entitlements (app groups, keychain groups, ordering)
- Info.plist (ATS, permissions, background modes)
- Relay env handling + gitignore + pycache hygiene
- Data validation layers (relay band, app decode guard, sanitizer)
Recurring checks
Run before every release:
# secrets in working tree
grep -rniE "api[_-]?key|client[_-]?secret|password|token" FuelBoard/ Shared/ FuelBoardWidgets/ --include="*.swift"
# secrets in git history (both repos)
git grep -ilE "client_secret|api_key|password" $(git rev-list --all) | head
# binary leak check (after build)
strings <app-binary> | grep -iE "192\.168|100\.120|client_secret|api_key"