All 20 checks with why-it-matters prose, severity, and cross-references to related audits.
Without a local persistence library, your app stores all data in memory — which evaporates the moment the OS terminates the process. Users lose cart contents, form drafts, or session state on every background cycle. On mobile, the OS kills backgrounded apps aggressively; an app with zero local storage is effectively stateless. ISO 25010:2011 reliability.recoverability scores zero when there is nothing to recover. Beyond UX frustration, this is an architectural gap: offline-first patterns, crash recovery, and conflict resolution all presuppose that at least one store/retrieve call site exists.
Why this severity: Critical because a total absence of local persistence means every app restart silently destroys user data with no recovery path.
mobile-offline-storage.data-persistence.storage-library-presentSee full patternPersisting only an auth token while leaving user profile, form progress, and app state in memory creates a class of silent data loss that frustrates users and erodes retention. When the OS terminates your app — which happens routinely on low-memory devices — anything not written to storage is gone. ISO 25010:2011 reliability.recoverability requires that at least three critical data categories survive an unexpected termination. Apps that fail here force users to repeat onboarding flows, re-enter form data, and lose context — all of which correlate directly with abandonment.
Why this severity: Critical because in-memory-only state means any OS-triggered termination silently destroys user progress across multiple data categories with no recovery path.
mobile-offline-storage.data-persistence.data-persisted-lifecycleSee full patternWhen every data query requires a live network round-trip, users on flaky connections — subways, elevators, rural areas — get a blank or broken screen. Mobile network reliability is not a product assumption; it is a variable you must handle. ISO 25010:2011 reliability.fault-tolerance and recoverability both penalize apps that have no local query path. Beyond connectivity, local queries are also faster by orders of magnitude: a SQLite `SELECT` takes microseconds; a network call takes hundreds of milliseconds even on good connections. An offline query layer is the foundation for every other pattern in this bundle.
Why this severity: Critical because apps with no offline query capability become completely unusable without network access, blocking users from data they already have on-device.
mobile-offline-storage.data-persistence.local-queries-work-offlineSee full patternAn app that crashes or resets to empty state when encountering corrupted or missing persisted data — a realistic scenario after OS updates, storage migrations, or unexpected terminations — forces users into a hard logout or blank screen. CWE-755 (Improper Handling of Exceptional Conditions) applies directly: failing to catch parse errors on startup is a class of unhandled exception that destroys user sessions. ISO 25010:2011 reliability.recoverability requires a defined degradation path when restore fails. The business impact is measurable: every startup crash from a missing try/catch translates to an uninstall.
Why this severity: High because an unguarded state restoration failure converts a routine app relaunch into a crash or silent data reset, directly causing user abandonment.
mobile-offline-storage.data-persistence.state-restorationSee full patternWithout active network detection, your app has no basis for deciding when to serve cached data, queue actions, or display an offline banner. Blind network calls on a disconnected device generate unhandled promise rejections that ripple into broken UI states. ISO 25010:2011 reliability.fault-tolerance requires apps to detect and respond to connection loss at runtime. The absence of a NetInfo or equivalent listener means every network-dependent feature silently fails rather than gracefully degrading — a qualitatively worse user experience than a clear offline indicator.
Why this severity: High because without connectivity detection, all network-dependent features fail silently, leaving users with no feedback and no path to offline functionality.
mobile-offline-storage.offline-behavior.network-detectionSee full patternWithout a visible offline indicator, users cannot distinguish between a live response and stale cached data, so they act on outdated inventory, prices, messages, or bookings and then blame the app when their changes silently fail to reach the server. This erodes trust fast on flaky cellular connections, drives one-star reviews tied to 'lost my data,' and undermines the user-experience taxon by hiding a critical system state. Support tickets spike because users assume a hang is a crash.
Why this severity: Medium because the defect corrupts user decision-making and trust but does not directly leak data or break security.
mobile-offline-storage.offline-behavior.offline-ui-indicatorSee full patternWhen a user submits a form or triggers a mutation while offline and the app silently drops the request, data is lost without notice. This is both a trust failure and a functional defect. CWE-362 (Concurrent Execution Race Condition) applies when reconnect occurs mid-action without a serialized queue: the same action can fire multiple times or not at all. An offline action queue with local storage persistence ensures user intent is preserved across connectivity gaps, reconnects, and app restarts — a baseline requirement for any app used in variable-network environments.
Why this severity: Medium because dropped offline mutations cause silent data loss, but the immediate impact is bounded to the current session rather than enabling cross-user exploitation.
mobile-offline-storage.offline-behavior.action-queueingSee full patternA reconnect that fires while a previous sync is still in progress can submit the same queued action twice — a duplicate order, a duplicate payment, or a duplicate form entry. CWE-362 (Race Condition) and CWE-694 (Use of Multiple Primitives to Lock a Resource) both apply to queue processing without deduplication guards. Without idempotency keys, network flicker during sync transforms a reliability feature into a correctness hazard. On APIs that charge per-request or trigger side effects (emails, webhooks, charges), duplicates have direct financial and trust consequences.
Why this severity: High because duplicate submissions during reconnect can trigger double charges, double emails, or duplicate records — failures that are difficult to reverse and immediately visible to users.
mobile-offline-storage.offline-behavior.duplicate-preventionSee full patternRunning sync operations synchronously on the JavaScript thread blocks the event loop, freezing animations, touch responses, and navigation during large data transfers. ISO 25010:2011 performance-efficiency.time-behaviour requires that background operations do not degrade foreground frame rate. A frozen UI during sync is indistinguishable from a crash for the user — they force-quit the app, potentially interrupting the sync and corrupting queue state. Sync must be non-blocking even when processing hundreds of queued records.
Why this severity: Medium because UI freezes degrade perceived reliability and can interrupt sync mid-flight, but the defect does not expose data or enable exploitation.
mobile-offline-storage.offline-behavior.non-blocking-syncSee full patternAn app that does not automatically sync on reconnect forces users to manually pull-to-refresh or restart the app to see changes made on another device or from the server. CWE-362 applies when the window between going offline and reconnecting allows remote state to diverge without the client knowing. ISO 25010:2011 reliability.recoverability requires that the app reaches a consistent state after a connectivity gap without user intervention. In collaborative or multi-device scenarios, the failure to auto-sync on reconnect means users work on stale data, potentially overwriting remote changes.
Why this severity: High because missing auto-sync on reconnect leaves local and remote state silently diverged, which can cause data overwrites or user confusion in multi-device scenarios.
mobile-offline-storage.sync-conflicts.data-sync-on-reconnectSee full patternWhen a user edits data offline while the server receives a concurrent update from another session, a Last-Write-Wins strategy without field-level timestamps will silently discard one of the changes. CWE-362 (Race Condition) and CWE-694 are both implicated. ISO 25010:2011 reliability.recoverability requires that the system resolves conflicts without data loss. The failure mode is particularly damaging in collaborative tools or multi-device workflows: users believe their changes were saved, but the data they see after sync reflects a different device's state. Silent data loss is harder to detect than visible errors and more damaging to user trust.
Why this severity: High because unresolved sync conflicts cause silent data loss or overwrites, which users discover only after the damage is done and may not be recoverable.
mobile-offline-storage.sync-conflicts.conflict-resolution-strategySee full patternA cache with no invalidation strategy serves stale data indefinitely. After a server-side update — price change, policy revision, content correction — users continue seeing the cached version until they clear app data or reinstall. ISO 25010:2011 reliability.recoverability requires a defined freshness boundary. Beyond staleness, unbounded caches accumulate sensitive data (PII, session-specific content) that should have been evicted after use. GDPR Art. 32 expects that personal data is not retained beyond its necessary lifetime — a cache without TTL enforcement is a retention policy violation by omission.
Why this severity: High because indefinitely-cached data can include stale PII or pricing that misleads users and may violate GDPR Art. 32 data minimization obligations.
mobile-offline-storage.sync-conflicts.cache-invalidationSee full patternA sync that processes records sequentially without transaction semantics can leave the local database in a partially-updated state if the process is interrupted mid-way. CWE-362 applies when an interrupted sync produces orphaned references — a local record pointing to a remote entity that was never fetched. ISO 25010:2011 reliability.recoverability requires that interrupted operations leave data in a valid, queryable state. The failure mode is subtle: the app appears to function normally after the crash, but relationship integrity is broken and queries silently return incomplete results.
Why this severity: Medium because partial sync failures corrupt relational integrity locally, but the exposure is confined to the affected device rather than the server or other users.
mobile-offline-storage.sync-conflicts.partial-sync-safetySee full patternStoring auth tokens, API keys, or PII in AsyncStorage writes plaintext to the device filesystem with no access controls beyond the app sandbox. On a rooted or jailbroken device — a realistic threat model, not an edge case — any process can read AsyncStorage without authentication. CWE-311 (Missing Encryption of Sensitive Data) and CWE-312 (Cleartext Storage of Sensitive Information) directly describe this defect. OWASP Mobile Top 10 M9 and GDPR Art. 32 both mandate encryption for personal data at rest. A compromised device that exposes a plaintext refresh token enables full account takeover; the attacker does not need the user's password.
Why this severity: Critical because plaintext token storage in AsyncStorage exposes credentials to any process on a rooted device, enabling account takeover without requiring the user's password.
mobile-offline-storage.storage-security.encryption-at-restSee full patternA plaintext SQLite database file is readable by anyone with filesystem access to the device — a physical attacker, a forensic tool, or malware with elevated privileges. CWE-311 (Missing Encryption of Sensitive Data) and CWE-922 (Insecure Storage of Sensitive Information) both apply. OWASP Mobile Top 10 M9 and GDPR Art. 32 require encryption for stored personal data. Unlike AsyncStorage, a SQLite file is a structured, easily-parsed binary that can be opened in any standard tool. A single extracted database file exposes the entire local data model with no further attack required.
Why this severity: High because an unencrypted database file can be extracted from a compromised device and parsed trivially, exposing all stored personal data with no additional attack.
mobile-offline-storage.storage-security.database-encryptionSee full patternStoring JWT access tokens or refresh tokens in AsyncStorage or UserDefaults writes them as plaintext accessible to any process with filesystem access on a rooted device. CWE-312 (Cleartext Storage of Sensitive Information) and CWE-522 (Insufficiently Protected Credentials) both apply. NIST SP 800-53 IA-5 requires cryptographic protection of authenticators at rest. GDPR Art. 32 mandates appropriate technical measures for personal data — an unprotected refresh token is a credential, and its exposure enables persistent account takeover after the original access token expires.
Why this severity: High because a plaintext refresh token in AsyncStorage on a compromised device grants an attacker persistent, renewable access to the user's account.
mobile-offline-storage.storage-security.secure-token-storageSee full patternA cache with no TTL enforcement retains data beyond its useful life — including sensitive content like user-specific feeds, prices, or session artifacts. CWE-922 (Insecure Storage of Sensitive Information) applies when cached data persists longer than the context that authorized it: a logged-out user's next session can read the previous user's cached content if the cache is never expired. ISO 25010:2011 reliability.recoverability is also impacted — stale data served from an indefinite cache is indistinguishable from fresh data, making correctness impossible to guarantee after server-side updates.
Why this severity: Low because cache staleness primarily causes UX and correctness issues rather than direct exploitation, though indefinite retention of session-scoped data is a secondary security concern.
mobile-offline-storage.storage-security.cache-expirationSee full patternWhen sync is fully automatic with no manual escape hatch, users who suspect stale data — a merchant checking a just-placed order, a field technician pulling the latest work ticket — have no way to force a refresh and must kill the app or wait for an opaque background timer. This produces 'the app is broken' perception even when the sync engine is healthy, and it blocks power users from recovering from transient failures. The user-experience taxon depends on giving users visible control over system state.
Why this severity: Low because automatic sync still works; the gap is user confidence and recovery, not data loss or security.
mobile-offline-storage.offline-behavior.manual-sync-triggerSee full patternStored records without timestamps or source markers make it impossible for the app to determine whether cached data is fresh, which copy won a conflict, or whether a local edit has been synced. ISO 25010:2011 reliability.recoverability requires that the system can determine the state of data after a failure — impossible without creation and modification timestamps. Without a `source` marker, merge logic cannot distinguish local-only edits from server-authoritative records. This undermines every higher-order pattern in this bundle: cache invalidation, conflict resolution, and sync-on-reconnect all require metadata to make correct decisions.
Why this severity: Low because missing metadata degrades offline correctness and merge reliability rather than enabling direct exploitation, but it undermines every other sync-safety pattern.
mobile-offline-storage.data-persistence.data-metadataSee full patternAn app with no storage quotas or cleanup logic accumulates cache data indefinitely. On devices with limited storage — a real constraint on mid-range and older Android handsets — this causes the OS to terminate the app, deny further writes, or prompt the user to clear data. ISO 25010:2011 performance-efficiency.resource-utilisation requires that apps bound their resource footprint. Beyond the device-health impact, unbounded storage growth retains data that should have been evicted: stale records, orphaned queue items, and superseded cache entries that inflate the attack surface for physical device compromise.
Why this severity: Low because storage accumulation degrades device health and UX over time rather than enabling immediate exploitation, but it becomes a reliability defect on constrained devices.
mobile-offline-storage.storage-security.storage-limitsSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Mobile Offline & Storage Audit