API key stored insecurely in localStorage — accessible to XSS and same-origin scripts #6

Closed
opened 2026-05-09 05:18:01 +00:00 by Mark · 0 comments
Owner

Severity: High

Files: src/hooks/useWizard.tsx, src/lib/oauth.ts

Issues:

1. API Key in localStorage (useWizard.tsx)

The entire WizardState — including apiKey — is serialized and stored in localStorage under key gsd-wizard-state. localStorage is accessible to any JavaScript running on the same origin. An XSS vulnerability anywhere in the app would expose the user's API keys.

2. OAuth Token "Encryption" is XOR obfuscation (oauth.ts)

The encryptTokens function uses:

const ENCRYPTION_KEY = 'gsd2-oauth-encryption-key-v1';
// ... simple XOR obfuscation

This is NOT encryption — it is trivially reversible XOR with a hardcoded key visible in the source code. Anyone with access to the browser or source can decrypt stored OAuth tokens.

Recommendations:

  1. Store sensitive tokens in sessionStorage (already partially done for OAuth, but wizard state uses localStorage)
  2. Use proper Web Crypto API encryption with a per-session key (e.g., derived from a short-lived secret)
  3. Or use HTTP-only cookies if there was a backend
  4. Never store unencrypted API keys in persistent storage
**Severity:** High **Files:** `src/hooks/useWizard.tsx`, `src/lib/oauth.ts` **Issues:** ### 1. API Key in localStorage (useWizard.tsx) The entire `WizardState` — including `apiKey` — is serialized and stored in localStorage under key `gsd-wizard-state`. localStorage is accessible to *any* JavaScript running on the same origin. An XSS vulnerability anywhere in the app would expose the user's API keys. ### 2. OAuth Token "Encryption" is XOR obfuscation (oauth.ts) The `encryptTokens` function uses: ```typescript const ENCRYPTION_KEY = 'gsd2-oauth-encryption-key-v1'; // ... simple XOR obfuscation ``` This is NOT encryption — it is trivially reversible XOR with a hardcoded key visible in the source code. Anyone with access to the browser or source can decrypt stored OAuth tokens. **Recommendations:** 1. Store sensitive tokens in `sessionStorage` (already partially done for OAuth, but wizard state uses localStorage) 2. Use proper Web Crypto API encryption with a per-session key (e.g., derived from a short-lived secret) 3. Or use HTTP-only cookies if there was a backend 4. Never store unencrypted API keys in persistent storage
Mark 2026-05-20 12:44:26 +00:00
Sign in to join this conversation.
No description provided.