Security Model

This describes SenseBridge’s security posture and threat model — what could go wrong and what mitigates it — not a list of live findings. Specific, unresolved security findings are tracked privately rather than published here; see SECURITY.md for how to report one.

Why the attack surface is small by construction

SenseBridge’s MVP has no backend, no accounts, and no telemetry by default — see docs/ARCHITECTURE.md. That is an architectural fact, not a policy promise, and it removes most of the classic attack surface before any code is written: no server to breach, no database to leak, no session or auth system to attack, and no cross-user data to leak between accounts, because there are no accounts. What remains in scope is what’s on the device itself, and what’s used to build and ship it — both covered below.

The outbound paths. Two, both opt-in and off by default, so an install that has not been touched has exactly the surface described above.

Since 2026-07-31 the app links Sentry for crash reporting, starting only when the user switches on Settings → Diagnostics. When it is on, the addition to the threat model is: a third-party SDK with signal and exception handlers installed, and an HTTPS egress to Sentry’s ingest endpoint carrying stack traces, device model, and OS/app version. Breadcrumbs, screenshots, view hierarchies, network tracking, and method swizzling are all disabled in code, and CrashReporting.scrub strips user, request, server-name, and device-name fields before transmission. See docs/PRIVACY.md and app/SenseBridge/App/CrashReporting.swift.

Since 2026-08-11 the app also supports opt-in Local (self-hosted) or Cloud (BYOK: Anthropic, OpenAI, NVIDIA NIM) reasoning backends, starting only when the user explicitly switches Settings → Reasoning backend away from On-Device and, for Cloud, acknowledges that provider’s own terms. The addition to the threat model when active: an HTTPS (or, for a Local endpoint the user points at their own LAN server, HTTP under a scoped NSAllowsLocalNetworking exception — never NSAllowsArbitraryLoads) egress carrying recognized object labels only, never camera images, audio, depth data, or location — PerceptionRecord.detectedObjectLabelsForNetwork() is the one function that builds that payload. ReasoningOutputValidator inspects every response before it can reach spoken output, rejecting anything that isn’t a short, hedge-free noun phrase, so a compromised or malicious endpoint’s reply is a rejected request, not spoken injected text. Credentials are Keychain-only (kSecAttrAccessibleWhenUnlockedThisDeviceOnly, excluded from iCloud sync), never UserDefaults or a log. See docs/PRIVACY.md and docs/superpowers/specs/2026-08-11-awareness-ai-tiers-design.md.

Trust boundaries

Device sensors (camera, microphone) → Perception → Reasoning → Output
                                                        |
                                          On-device storage (UserDefaults)
                                                        |
                              (opt-in, disabled by default) Cloud Reasoning
                                  Adapter — user's own provider credential

Threat model

Assets worth protecting

Plausible adversaries and what mitigates each

Adversary What they’d want Mitigation
A device thief / someone with physical access Anything cached on the device No persisted user content by design (images/text are processed and discarded); any future enrollment store is encrypted with Keychain-protected keys behind device unlock
A malicious or compromised dependency Code execution, data exfiltration via a bundled package or model Minimal SwiftPM dependency tree, Dependabot + OSV scanning, pinned versions, and the dependency-auditor review path (see “Supply chain” below)
A future misconfigured opt-in cloud provider Camera imagery or recognized text sent off-device The adapter is disabled by default and requires explicit opt-in; per doctrine 2 in AGENTS.md, nothing about the user’s surroundings leaves the phone without consent and a privacy-doc update
A committer accidentally exposing a credential CI or signing secrets in the repo, a log, or a built artifact Three independent scanners (gitleaks pre-commit, TruffleHog + GitGuardian in CI) plus tools/check-sensitive-files.mjs; see “Secrets posture” below

Supply chain

Secrets posture

The app itself ships no secrets — it is serverless and holds no API keys or credentials of its own. What secrets exist live entirely in CI and local developer tooling:

Permissions

Verified against app/SenseBridge/Resources/InfoPlist.xcstrings and the capture code that requests each one:

Permission Usage description Justification
NSCameraUsageDescription “SenseBridge uses the camera to read text and describe scenes for you. Nothing leaves your device.” Actively used by two paths, both on-device. CameraSource (app/Packages/SenseBridgeCore/.../Sensing/CameraSource.swift) requests camera authorization and drives the Read/Identify/Describe capture flows. AmbientSensingSource (.../Sensing/AmbientSensingSource.swift) runs an ARWorldTrackingConfiguration with .sceneDepth for Obstacle Awareness — ARSession is the only API returning a camera frame and a registered depth map from one session, and it consumes the same camera grant rather than a separate one. The camera image itself never leaves the device under any setting — the “Nothing leaves your device” claim above is about the frame, not about what’s derived from it: since 2026-08-11 a user who opts into a Local/Cloud reasoning backend sends the object labels Vision recognized in that frame, never the frame. See the network-reasoning exception above.
NSMicrophoneUsageDescription “SenseBridge uses the microphone to recognize nearby sounds and announce them. Nothing leaves your device.” Actively used: MicrophoneSensingSource (app/Packages/SenseBridgeCore/.../Sensing/MicrophoneSensingSource.swift) requests microphone authorization and feeds SoundAlertsView through CombinedSoundClassifier (CustomSoundClassifier + BuiltInSoundClassifier, run concurrently on one capture). Classification is on-device; audio is captured per tap for a bounded duration, never streamed, written to disk, or transmitted.

No other NS*UsageDescription keys exist in the current build — no photo library, location, Bluetooth, or biometric-hardware access is requested.

Reporting a vulnerability

Report security issues privately — see SECURITY.md at the repository root for what’s in scope and how to report. Do not open a public issue for a vulnerability.

Data handling

The guarantees around what happens to user content — what’s processed and discarded, what’s never logged, what optional sync does and doesn’t carry — live in docs/PRIVACY.md. This page describes the security posture that backs those guarantees; it does not restate them.


Need help? See SUPPORT.md.