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

ImpactDetails
ConfidentialityScope: Confidentiality

Read Application Data - Attackers can read sensitive information by accessing the unrestricted storage mechanism.
IntegrityScope: 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;
    }
}

  • 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

  1. MITRE Corporation. "CWE-921: Storage of Sensitive Data in a Mechanism without Access Control." https://cwe.mitre.org/data/definitions/921.html
  2. OWASP. "Insecure Data Storage." https://owasp.org/www-project-mobile-top-10/
  3. Android Developers. "Data and file storage overview." https://developer.android.com/training/data-storage