menu
close_24px

BLOG

Exposing iOS Local Storage Flaws: A Guide to Securing Sensitive Data

Discover the risks of insecure iOS data storage and learn best practices to secure NSUserDefaults, Keychain, SQLite, Realm, and Couchbase Lite. Includes secure code snippets, data points, and developer FAQs.
  • Posted on: Sep 24, 2025
  • By Prudhvi Chaitanya Depuru
  • Read time 8 Mins Read
  • Last updated on: Sep 24, 2025

Introduction

Mobile apps often handle sensitive data daily, such as credentials, tokens, health records, financial information, and personal identifiers that attackers seek to exploit. 

On iOS, developers sometimes assume local data storage is inherently secure because of sandboxing and built-in Apple protections. This assumption is flawed.

Poorly implemented storage practices can expose critical data, leading to severe privacy and security incidents.

This article examines 

  • How insecure local data storage occurs in iOS applications, 
  • The specific risks across different storage mechanisms, and 
  • The technical countermeasures that developers and security teams must adopt to mitigate these threats.

Key takeaways: Securing iOS local storage

 
  • Local storage is not inherently safe. iOS sandboxing isn’t enough. Attackers can still extract sensitive data with basic forensic tools.
  • NSUserDefaults is a trap. Never store passwords, tokens, or keys in NSUserDefaults, as it saves data in plaintext plist files.
  • Use Keychain the right way. Stick to SecAttrAccessibleWhenUnlockedThisDeviceOnly or stricter; avoid Always attributes.
  • Encrypt all databases. SQLite (with SQLCipher), Realm, and Couchbase Lite all require explicit encryption setup. Defaults are insecure.
  • Don’t trust logs & caches. Remove sensitive data from logs, disable predictive keyboard caching, and prevent iOS screenshots from capturing private views.
  • Follow MASVS & Apple’s guidelines. Map your app’s storage strategy against OWASP MASVS and Apple’s official data protection rules to avoid compliance gaps.
  • Defense-in-depth is mandatory. Combine keychain, database encryption, and logging/caching controls to close the most common exploit paths.

Understanding insecure data storage in iOS apps

Insecure data storage refers to storing sensitive information on a device without strong protection. 

Attackers with device access—physical theft, malware, or remote compromise—can extract this data using forensic tools, jailbreak techniques, or even basic device backups. Once retrieved, the data may allow account takeover, identity theft, or further lateral movement.

Factors contributing to insecure storage

The primary contributors to insecure storage are:

  • Saving unencrypted data in plaintext containers
  • Relying on weak or default encryption configurations
  • Storing excessive logs or cached information unnecessarily
  • Ignoring secure APIs and platform guidelines

Data storage in iOS

In iOS applications, data can be stored in various locations, including:

  • NSUserDefaults
  • Unsecured Keychains data
  • SQLite Databases
  • CoreData
  • Yap Database
  • Couchbase Lite Databases
  • Background caching of screenshots
  • Logging

Risks in common iOS data storage mechanisms

 

NSUserDefaults

NSUserDefaults provides a convenient way for iOS applications to store user preferences and lightweight data, but it has significant security vulnerabilities if misused. 

Risks in using NSUserDefaults

Many developers inadvertently store sensitive information, such as authentication credentials, API keys, or personally identifiable information (PII), in NSUserDefaults, not realizing that this data is stored in an unencrypted property list or plist file located in the application's ”/Library/Preference/“ directory. 

Moreover, the data stored in NSUserDefaults is not protected by iOS keychain services, making it vulnerable to unauthorized access and manipulation, particularly on jailbroken devices. 

If an attacker were to access this file, they could potentially steal user credentials, modify application settings, or bypass established security protocols.

Secure approach

Tools like iExplorer or simple device backups can extract this data within seconds.

Unsecured Keychains data

Sensitive data can be exposed in a keychain with inappropriate accessibility settings. While Apple’s Keychain is the recommended place for storing sensitive credentials, improper configuration undermines its security. 

Risks in unsecured keychain data

Developers often use kSecAttrAccessibleAlways, which keeps items available even when the device is locked, creating exposure. Weak access controls or misconfigurations in group sharing can also allow data leakage between apps.

SQLite databases

SQLite is an open-source SQL database that stores data in a text file on a device. It supports all the features of a relational database and is widely used for structured app data.

Storing sensitive data, such as user credentials, session tokens, and API keys, can expose this data to other applications or a superuser, as no authentication is required to access it. 

Risks in SQLite databases

Unencrypted SQLite files are easily extracted using forensic tools. Metadata, query history, and complete records—including PII or financial details—can be recovered. 

The SQLite engine does not have built-in security to protect databases. Instead, it relies on its environment, such as the operating system, to provide security for database content. 

Secure approach

All data being stored in the database must be verified and secured.

CoreData

Core Data is a framework for managing the model layer of objects in your application. It serves as a means for applications to store data for use in subsequent stages of operation. 

Risks in CoreData

CoreData is often backed by SQLite. These databases do not have built-in encryption features, meaning all information is stored in plain text within the files. 

As a result, if an application saves user credentials or other sensitive personal information in this database, it is vulnerable to unauthorized access. Attackers can traverse schema and entity relationships, reconstructing user activity or private content.

Realm databases

The Realm databases are stored as files with the .realm extension, and they are located within the file system at the specific path:

/Application/Containers/Data/Application/<AppID>/Documents/default.realm

This path is part of the app's sandboxed environment on iOS devices, which is designed to isolate app data from other applications. 

However, on jailbroken devices, this sandboxing can be bypassed, allowing malicious actors to navigate the file system and access these .realm files directly.

Risks in Realm databases

Realm databases store data in a binary format, but without enabling built-in encryption, the files remain unprotected. Attackers with file system access can parse these files. 

Developers may neglect Realm’s encryptionKey configuration, leaving the database equivalent to plaintext.

Yap Database

YapDatabase is a high-performance, key-value database for iOS and macOS applications, often used as an alternative to Core Data or Realm. YapDatabase offers robust features, including caching, automatic serialization, and multithreading. 

As a result, if an application uses this database to store user credentials or other sensitive information, such data could be at risk of being accessed by unauthorized third parties.

Risks in the Yap database

By default, the Yap database stores data in plain text. Sensitive objects stored here can be extracted directly. 

Without explicit encryption layers, Yap provides no inherent guarantees of confidentiality.

Couchbase Lite databases

Couchbase Lite is a compact, embedded, document-oriented (NoSQL) database engine that supports synchronization. Couch databases serve as storage solutions for applications, allowing them to retain data for future use. The files associated with the database, particularly those that carry the ".cblite" extension.

Risks in Couchbase Lite databases

These databases lack integrated encryption capabilities, resulting in all stored information being in plain text. 

If developers skip implementing the database’s full encryption API, local documents—including offline caches—remain fully exposed. The sensitive data in this application's database is, therefore, vulnerable to unauthorized access.

Caching of Screenshots

When an iOS app moves to the background, the operating system captures a screenshot of the current user interface to ensure a smooth return to the app. 

While this feature enhances the user experience, it can raise security issues if sensitive information, such as financial details, personal data, or authentication screens, appears in the background image. 

The cached screenshots are located within the file system at the specific path:

/Application/Containers/Data/Application/<AppID>/Library/SplashBoard/Snapshots/sceneID:*/

Security issues with the caching of screenshots

iOS captures app screenshots for fast app switching. These images may inadvertently include sensitive data like transaction details, OTPs, or chat messages. 

Without mitigation, screenshots are stored unprotected and can be extracted from device backups or memory dumps.

Logging

NSLog is an essential function for iOS developers, widely used to debug iOS applications. It enables developers to check variable values, record essential notes, and pinpoint errors when a debugger isn't available. 

While NSLog is useful during the development stage, it is crucial to disable it before launching the app in production. Keeping NSLog active in the production version could expose logged information to potential attackers who might access the physical device or other applications on a jailbroken device.

Log files can be generated through various methods. The subsequent list outlines the options available on iOS:

  • NSLog Method
  • printf-like function
  • NSAssert-like function
  • Macro

Security risks from logging (NSLog and others)

Verbose logging often leaks sensitive runtime data, including tokens, request payloads, headers, and errors.

NSLog output persists in device logs and can be accessed via Xcode or third-party tools. On jailbroken devices, attackers can systematically harvest this information.

Keyboard cache

iOS offers a seamless and sophisticated keyboard experience, incorporating functionalities such as auto-correction, predictive text, and keyboard caching. 

A range of options, including autocorrect and spell check, is provided to users to streamline keyboard input. These options are, by default, cached in .dat files in the “/private/var/mobile/Library/Keyboard/” folder and its associated subdirectories. 

The implementation of these features, including passwords, credit card details, or personal data.

Risks from keyboard cache

The iOS keyboard learns and caches typed input to improve suggestions. 

If not handled carefully, the implementation of keyboard caching may pose security vulnerabilities when managing sensitive information, including passwords, credit card numbers, or PII, which may be retained in the predictive text cache. 

Attackers with device access can dump this cache and recover sensitive strings.

Summary table: Insecure storage risks in iOS 

Storage mechanism

Common mistake

Real-world example

Impact

Secure practice

NSUserDefaults

Storing passwords or tokens in a plist

Extractable via iTunes backup

Account takeover

Only store lightweight preferences

Keychain

Using AccessibleAlways

Credentials are readable when locked

Unauthorized access

Use WhenUnlockedThisDeviceOnly

SQLite / CoreData

No encryption (default)

PII extracted with forensic tools

Identity theft, fraud

Use SQLCipher or file-level encryption

Realm

Not enabling encryptionKey

Plaintext Realm DB files

Sensitive data exposure

Configure encryption at initialization

Couchbase Lite

Default unencrypted files

Offline caches fully exposed

Data leaks & sync risks

Enable Couchbase Lite’s encryption API

Caching / Temp files

Sensitive data in /tmp or screenshots

Telegram cached deleted media

Private data recovery

Encrypt temp data, disable screen capture

Logging (NSLog)

Tokens or payloads logged

Readable via Xcode or jailbreak tools

Token hijack, replay attacks

Disable verbose logging in production

Keyboard Cache

PII in predictive cache

Passwords recovered from keyboard logs

Credential leaks

Disable autocorrect + secure text entry

 

Expert opinion

Abhinav VasisthWebinar (2)

001-linkedin-1

Abhinav Vasisth, Appknox’s Security Research Lead, believes that

“Developers often underestimate local storage risks on iOS, assuming the sandbox is enough. But attackers exploit weak configurations, not just OS flaws.”

How to prevent insecure data storage in iOS apps?

Preventing insecure storage requires a defense-in-depth approach, combining secure APIs, strong encryption, and strict access controls. 

Below are practical strategies, along with implementation snippets, that developers can apply immediately.

1. Use Keychain securely

Store credentials and tokens only in Keychain. Configure accessibility with kSecAttrAccessibleWhenUnlocked or a stricter setting, never Always.

Swift example

let account = "user@example.com"
let password = "SuperSecurePass!".data(using: .utf8)!
let query: [String: Any] = [

kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecValueData as String: password,

kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]

let status = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
print("Securely stored in Keychain")
}

2. Encrypt all databases

SQLite with SQLCipher

PRAGMA key = 'super_secret_key';

Realm encryption setup

var config = Realm.Configuration()
let key = Data(count: 64)
_ = key.withUnsafeBytes { SecRandomCopyBytes(kSecRandomDefault, 64, $0.baseAddress!) }

config.encryptionKey = key
let realm = try! Realm(configuration: config)

Couchbase Lite encryption

let config = DatabaseConfiguration()
config.encryptionKey = EncryptionKey(password: "super_secret_key")
let database = try Database(name: "secure-db", config: config)

3. Secure cached and temporary data

Avoid writing secrets to /tmp or /Library/Caches. 

If required, encrypt before writing.
let sensitiveData = "PII-data".data(using: .utf8)!
let encrypted = try AES.GCM.seal(sensitiveData, using: key).combined
try encrypted?.write(to: secureURL)

4. Implement screenshot protection

self.view.window?.isSecure = true

This prevents the app’s view from being captured in the app switcher.

5. Control logging

Remove sensitive data from logs. For production builds:

#if DEBUG
print("Debug info: \(debugData)")
#endif

6. Protect against keyboard caching

textField.isSecureTextEntry = true
textField.autocorrectionType = .no
textField.spellCheckingType = .no

textField.smartInsertDeleteType = .no

7. Leverage platform crypto libraries

Use CryptoKit instead of rolling custom crypto.

import CryptoKit

let key = SymmetricKey(size: .bits256)
let data = "Sensitive Info".data(using: .utf8)!
let sealedBox = try! AES.GCM.seal(data, using: key)

8. Adopt secure coding guidelines


  • Follow Apple’s Data Protection and App Security guidelines.
  • Map implementations against OWASP MASVS (Mobile App Security Verification Standard)

Conclusion: Building secure iOS apps with proper data storage

Local storage is often underestimated in iOS threat modeling. 

Yet, forensic investigations consistently reveal apps leaking credentials, personal data, and tokens through insecure mechanisms. 

Attackers no longer require jailbreaks or advanced exploits. Many insecure storage flaws can be exploited with basic tools.

Developers must treat local storage with the same rigor as network security: never assume the device is safe. Encryption, restricted APIs, and data minimization should be non-negotiable. Security teams must integrate static and dynamic analysis into the SDLC to catch unsafe storage practices before release.

In the current mobile threat landscape, secure storage is no longer optional; it has become a baseline expectation for any app handling user data.

Frequently Asked Questions

 

1. Why is NSUserDefaults unsafe for storing sensitive data?

NSUserDefaults saves values in a plaintext .plist file inside the app’s container. Anyone with access to the device filesystem or backup can extract this data. It should only be used for non-sensitive preferences (e.g., UI settings, feature flags).

2. How can I securely store credentials in an iOS app?

Use the iOS Keychain with strict accessibility attributes such as kSecAttrAccessibleWhenUnlockedThisDeviceOnly. This ensures data is only available when the device is unlocked and cannot be migrated to other devices.

3. What is the best way to encrypt SQLite or Realm databases?

 
  • For SQLite, use SQLCipher, which provides transparent AES-256 encryption.
  • For Realm, configure an encryptionKey during initialization to enable file-level encryption.

4. How can I prevent sensitive data from appearing in iOS screenshots?

Mark sensitive views as secure by setting self.view.window?.isSecure = true. This prevents iOS from capturing those views when the app transitions to the background.

5. What are the most common mistakes developers make with iOS data storage security?

The top mistakes developers make with iOS data storage security are:

  • Storing secrets in NSUserDefaults or plaintext databases
  • Using weak Keychain accessibility options (Always)
  • Leaving sensitive logs enabled in production
  • Failing to enable encryption in Realm or Couchbase Lite
  • Overlooking cached data like keyboard input or app snapshots