95 lines
3.9 KiB
Markdown
95 lines
3.9 KiB
Markdown
# 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 private `192.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 `strings` scan 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.swift` and OAuth *documentation* comments in
|
||
`FuelPriceProvider.swift`).
|
||
- Relay: `CLIENT_ID`/`CLIENT_SECRET` read from environment only
|
||
(`app/main.py:31-32`); `.env` is gitignored; `__pycache__`/`*.pyc`
|
||
untracked; `.env.example` ships empty placeholders.
|
||
- Binary scan should show no private LAN data endpoint; expected network strings
|
||
include public GitHub raw URLs, `maps.apple.com`, and `group.com.apt.fuelboard`.
|
||
No credentials.
|
||
|
||
### 3. Price data hardening — PASS (three layers)
|
||
|
||
- Relay rejects out-of-band rows at the edge (`_fuel_price` 50–500 pence/litre).
|
||
- App drops out-of-band grades at decode (`FuelPriceProvider.decodeStations`,
|
||
previously `c1edd4d`).
|
||
- 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.shared` listed FIRST
|
||
(default access group), then `com.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 `NSAllowsArbitraryLoads` anywhere (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` + `NSLocationAlwaysAndWhenInUseUsageDescription`
|
||
both present with clear copy. The app deliberately does not include the
|
||
`location` value in `UIBackgroundModes`; 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
|
||
|
||
- [x] Source secret scan (app, widget, shared, relay, config)
|
||
- [x] Git history scan (all 43 commits, both repos)
|
||
- [x] Built binary string scan (app + widget)
|
||
- [x] Entitlements (app groups, keychain groups, ordering)
|
||
- [x] Info.plist (ATS, permissions, background modes)
|
||
- [x] Relay env handling + gitignore + pycache hygiene
|
||
- [x] Data validation layers (relay band, app decode guard, sanitizer)
|
||
|
||
## Recurring checks
|
||
|
||
Run before every release:
|
||
|
||
```bash
|
||
# 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"
|
||
```
|