Storage of Sensitive Data in a Mechanism without Access Control
Description
Storage of Sensitive Data in a Mechanism without Access Control occurs when software stores sensitive information in a file system or device that does not have built-in access control mechanisms. Storage media such as memory cards, floppy disks, CDs, USB drives, and external storage typically lack access restrictions. On mobile platforms like Android, external storage (SD cards) is globally readable and writable by other applications and can be accessed via USB connections or by physically removing the storage media. When sensitive data is stored in these unprotected locations, any application or user with physical access can read, modify, or delete the data.
Risk
Storing sensitive data without access controls exposes it to unauthorized access from multiple vectors. On mobile devices, any installed application can read externally stored data. Physical access to the device or storage media allows data extraction. USB debugging or mass storage mode enables computer access to the data. Attackers can modify stored data to manipulate application behavior or inject malicious content. Deleted data may be recoverable from unencrypted storage media. This vulnerability is particularly dangerous for applications handling credentials, personal information, financial data, or health records.
Solution
Store sensitive data only in locations with built-in access controls. On Android, use internal storage (app's private directory) instead of external storage. Encrypt sensitive data before storing it anywhere. Use platform-provided secure storage mechanisms (Keychain on iOS, Android Keystore). Implement file-level encryption with per-file keys. Verify storage location permissions before writing sensitive data. Consider data sensitivity classifications and storage policies. For data that must be externally stored, use strong encryption with properly managed keys. Never store credentials, tokens, or personally identifiable information in world-readable locations.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Attackers can read sensitive information by accessing the unrestricted storage mechanism. |
| Integrity | Scope: Integrity Modify Application Data - Attackers can modify or delete sensitive information by accessing the unrestricted storage mechanism. |
Example Code
Vulnerable Code
// Vulnerable: Android app storing data on external storage
public class VulnerableDataStorage {
public void saveSensitiveData(String data) {
// Vulnerable: External storage is world-readable
File externalDir = Environment.getExternalStorageDirectory();
File dataFile = new File(externalDir, "myapp/credentials.txt");
try (FileWriter writer = new FileWriter(dataFile)) {
writer.write(data); // Any app can read this!
} catch (IOException e) {
Log.e(TAG, "Error saving data", e);
}
}
public void saveApiKey(String apiKey) {
// Vulnerable: SharedPreferences on external storage
SharedPreferences prefs = getSharedPreferences(
Environment.getExternalStorageDirectory() + "/myapp/config",
Context.MODE_WORLD_READABLE // Deprecated and dangerous!
);
prefs.edit().putString("api_key", apiKey).apply();
}
}
// Vulnerable: iOS app storing data in unprotected location
class VulnerableDataManager {
func saveCredentials(username: String, password: String) {
// Vulnerable: Storing in Documents directory without protection
let documentsPath = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let credentialsFile = documentsPath.appendingPathComponent("credentials.json")
let credentials = ["username": username, "password": password]
let data = try? JSONEncoder().encode(credentials)
// Vulnerable: No encryption, no data protection class
try? data?.write(to: credentialsFile)
}
}
# Vulnerable: Desktop app storing data in temp directory
import tempfile
import json
class VulnerableConfig:
def save_config(self, api_key, database_password):
# Vulnerable: Temp directory is world-readable on many systems
config_path = tempfile.gettempdir() + '/myapp_config.json'
config = {
'api_key': api_key,
'db_password': database_password
}
with open(config_path, 'w') as f:
json.dump(config, f)
# Any user on the system can read this file
// Vulnerable: Windows app storing in public folder
public class VulnerableStorage
{
public void SaveSensitiveData(string data)
{
// Vulnerable: Public Documents folder is accessible to all users
string path = Environment.GetFolderPath(
Environment.SpecialFolder.CommonDocuments);
string filePath = Path.Combine(path, "MyApp", "sensitive_data.txt");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.WriteAllText(filePath, data); // Any user can read
}
}
// Vulnerable: Browser extension storing data in localStorage
class VulnerableExtension {
saveCredentials(username, password) {
// Vulnerable: localStorage is accessible to page scripts
// XSS attacks can steal this data
localStorage.setItem('username', username);
localStorage.setItem('password', password);
}
saveApiKey(key) {
// Vulnerable: Any script on the page can access this
localStorage.setItem('api_key', key);
}
}
Fixed Code
// Fixed: Android app using secure internal storage
public class FixedDataStorage {
private Context context;
public FixedDataStorage(Context context) {
this.context = context;
}
public void saveSensitiveData(String data) {
// Fixed: Use internal storage - only this app can access
File internalDir = context.getFilesDir();
File dataFile = new File(internalDir, "credentials.enc");
try {
// Fixed: Encrypt before storage
byte[] encryptedData = encrypt(data.getBytes());
try (FileOutputStream fos = new FileOutputStream(dataFile)) {
fos.write(encryptedData);
}
} catch (Exception e) {
Log.e(TAG, "Error saving data", e);
}
}
public void saveApiKey(String apiKey) {
// Fixed: Use EncryptedSharedPreferences
try {
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
sharedPreferences.edit().putString("api_key", apiKey).apply();
} catch (Exception e) {
Log.e(TAG, "Error saving API key", e);
}
}
// Fixed: Use Android Keystore for cryptographic keys
public void saveSecretKey(String keyAlias, SecretKey key) {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
keyStore.setEntry(keyAlias,
new KeyStore.SecretKeyEntry(key),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
);
} catch (Exception e) {
Log.e(TAG, "Error saving key", e);
}
}
}
// Fixed: iOS app using Keychain for sensitive data
import Security
class FixedDataManager {
func saveCredentials(username: String, password: String) {
// Fixed: Store password in Keychain
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: username,
kSecAttrService as String: "com.myapp.credentials",
kSecValueData as String: passwordData,
// Fixed: Require device unlock to access
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
// Delete any existing item
SecItemDelete(query as CFDictionary)
// Add new item
let status = SecItemAdd(query as CFDictionary, nil)
if status != errSecSuccess {
print("Error saving to Keychain: \(status)")
}
}
func saveToProtectedFile(data: Data, filename: String) {
let documentsPath = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let fileURL = documentsPath.appendingPathComponent(filename)
do {
// Fixed: Use complete protection - encrypted when device locked
try data.write(to: fileURL, options: .completeFileProtection)
} catch {
print("Error saving protected file: \(error)")
}
}
}
# Fixed: Desktop app using secure storage
import os
import json
from cryptography.fernet import Fernet
import keyring
class FixedConfig:
def __init__(self, app_name: str):
self.app_name = app_name
self._init_encryption_key()
def _init_encryption_key(self):
# Store encryption key in OS keyring
stored_key = keyring.get_password(self.app_name, 'encryption_key')
if stored_key:
self.fernet = Fernet(stored_key.encode())
else:
key = Fernet.generate_key()
keyring.set_password(self.app_name, 'encryption_key', key.decode())
self.fernet = Fernet(key)
def save_api_key(self, api_key: str):
# Fixed: Store sensitive values in OS keyring
keyring.set_password(self.app_name, 'api_key', api_key)
def save_database_password(self, password: str):
# Fixed: Store in OS keyring
keyring.set_password(self.app_name, 'db_password', password)
def save_config(self, config: dict):
# Fixed: Use user's private directory
config_dir = os.path.join(os.path.expanduser('~'), '.config', self.app_name)
os.makedirs(config_dir, mode=0o700, exist_ok=True) # Owner only
config_path = os.path.join(config_dir, 'config.enc')
# Fixed: Encrypt sensitive data
config_json = json.dumps(config)
encrypted = self.fernet.encrypt(config_json.encode())
with open(config_path, 'wb') as f:
f.write(encrypted)
# Fixed: Set restrictive permissions
os.chmod(config_path, 0o600)
// Fixed: Windows app using protected storage
using System.Security.Cryptography;
using System.IO;
public class FixedStorage
{
public void SaveSensitiveData(string data)
{
// Fixed: Use user's private AppData folder
string appDataPath = Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData);
string appPath = Path.Combine(appDataPath, "MyApp");
Directory.CreateDirectory(appPath);
string filePath = Path.Combine(appPath, "sensitive_data.bin");
// Fixed: Encrypt data using DPAPI (tied to user account)
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
byte[] encryptedData = ProtectedData.Protect(
dataBytes,
null, // Optional entropy
DataProtectionScope.CurrentUser // Only this user can decrypt
);
File.WriteAllBytes(filePath, encryptedData);
}
public string LoadSensitiveData()
{
string appDataPath = Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData);
string filePath = Path.Combine(appDataPath, "MyApp", "sensitive_data.bin");
if (!File.Exists(filePath))
return null;
byte[] encryptedData = File.ReadAllBytes(filePath);
byte[] decryptedData = ProtectedData.Unprotect(
encryptedData,
null,
DataProtectionScope.CurrentUser
);
return Encoding.UTF8.GetString(decryptedData);
}
}
// Fixed: Browser extension using secure storage
class FixedExtension {
async saveCredentials(username, password) {
// Fixed: Use extension's secure storage API
await chrome.storage.local.set({
credentials: {
username: username,
// Note: Still consider encrypting password
password: await this.encryptValue(password)
}
});
// chrome.storage.local is not accessible to page scripts
}
async encryptValue(value) {
// Use Web Crypto API for encryption
const key = await this.getOrCreateKey();
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: iv },
key,
new TextEncoder().encode(value)
);
return {
iv: Array.from(iv),
data: Array.from(new Uint8Array(encrypted))
};
}
async getOrCreateKey() {
// Store key in extension's local storage
const stored = await chrome.storage.local.get('encryptionKey');
if (stored.encryptionKey) {
return await crypto.subtle.importKey(
'raw',
new Uint8Array(stored.encryptionKey),
'AES-GCM',
false,
['encrypt', 'decrypt']
);
}
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const exported = await crypto.subtle.exportKey('raw', key);
await chrome.storage.local.set({
encryptionKey: Array.from(new Uint8Array(exported))
});
return key;
}
}
Related CWEs
- CWE-922: Insecure Storage of Sensitive Information (parent)
- CWE-312: Cleartext Storage of Sensitive Information (related)
- CWE-311: Missing Encryption of Sensitive Data (related)
- CWE-732: Incorrect Permission Assignment for Critical Resource (related)
References
- MITRE Corporation. "CWE-921: Storage of Sensitive Data in a Mechanism without Access Control." https://cwe.mitre.org/data/definitions/921.html
- OWASP. "Insecure Data Storage." https://owasp.org/www-project-mobile-top-10/
- Android Developers. "Data and file storage overview." https://developer.android.com/training/data-storage