# chrome.storage.sync not used for unencrypted passwords or secrets

- **Pattern:** `ab-001312` (`extension-data-privacy.storage-security.no-sync-secrets`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001312
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001312)

## Why it matters

`chrome.storage.sync` transmits data to Google's servers and replicates it across every browser the user is signed into. Storing an unencrypted API key, OAuth token, or password in sync storage means that credential is now held by Google and replicated to potentially untrusted devices. CWE-312 (Cleartext Storage of Sensitive Information) and CWE-313 (Cleartext Storage in a File or on Disk) both apply — the data is transmitted and stored by a third party outside the developer's control. OWASP 2021 A02 and GDPR Art. 32 require appropriate encryption for data at rest; syncing credentials in plaintext fails both standards.

## Severity rationale

Medium because unencrypted secrets in `chrome.storage.sync` are transmitted to Google's infrastructure and replicated to all the user's signed-in browsers — a single compromised device in the sync chain exposes the credential everywhere.

## Remediation

Never store passwords, tokens, or API keys in `chrome.storage.sync`. Use `chrome.storage.local` with encryption for any sensitive value:

```js
// BAD — syncs plaintext secret to Google's servers
chrome.storage.sync.set({ apiKey: 'sk-abc123' });

// GOOD — stays local, encrypted at rest
import { encrypt } from './crypto-utils.js';
const encrypted = await encrypt('sk-abc123', derivedKey);
chrome.storage.local.set({ encryptedApiKey: encrypted });
```

For non-sensitive preferences (theme, language, UI state), `chrome.storage.sync` is appropriate. Draw the line at any value that grants access to an external service or identifies the user.

## Detection

- **ID:** `no-sync-secrets`
- **Severity:** `medium`
- **What to look for:** Examine uses of `chrome.storage.sync` (which syncs data across user devices via Google account). Check whether any password, API key, auth token, or other sensitive secret is stored in `chrome.storage.sync` without encryption.
- **Pass criteria:** Count all `chrome.storage.sync.set` calls and list the keys stored. `chrome.storage.sync` is only used for non-sensitive data (preferences, settings, UI state) with 0% sensitive values. Any sensitive data (passwords, tokens) uses `chrome.storage.local` with encryption or is not synced at all.
- **Fail criteria:** Bearer tokens, API keys, or passwords found in `chrome.storage.sync` without encryption. Sensitive data is transmitted to Google's servers for sync.
- **Skip (N/A) when:** The extension does not use `chrome.storage.sync`, or it only stores non-sensitive preferences.
- **Detail on fail:** Name the sensitive data. Example: `"API key stored in chrome.storage.sync without encryption — will sync across user devices via Google account"` or `"OAuth token saved to chrome.storage.sync, exposing authentication across synced browsers."`
- **Remediation:** Use `chrome.storage.local` for sensitive data:

  ```js
  // BAD
  chrome.storage.sync.set({ apiKey: 'secret' });

  // GOOD
  chrome.storage.local.set({ encryptedApiKey: encryptedValue });
  ```

  Or don't sync sensitive data at all; keep it in memory or only in `chrome.storage.local` with encryption.

## External references

- cwe CWE-312
- cwe CWE-313
- owasp A02
- nist SC-28
- gdpr Art. 32

Taxons: cryptography-and-secrets

HTML version: https://auditbuffet.com/patterns/ab-001312
