This extension implements a multi-layered security system for storing sensitive API keys (OpenAI, Anthropic, OpenRouter) using industry best practices and OWASP 2024/2025 guidelines.
High-Level Architecture
+------------------------------------------------------------------+
| User Interface |
+--------------------------------+---------------------------------+
|
v
+------------------------------------------------------------------+
| API Key Manager |
| +--------------+ +---------------+ +----------------------+ |
| | Password | | Rate | | API Key | |
| | Validator | | Limiter | | Validator | |
| +--------------+ +---------------+ +----------------------+ |
+--------------------------------+---------------------------------+
|
+--------------------+--------------------+
v v v
+-------------------+ +--------------+ +----------------------+
| Crypto Service | | Device | | Session Cache |
| (AES-GCM + | | Binding | | (chrome.storage |
| PBKDF2 800k) | | Service | | .session) |
+---------+---------+ +------+-------+ +----------------------+
| |
v v
+------------------------------------------------------------------+
| Secure Storage (chrome.storage.local) |
| [Encrypted API Keys] |
+------------------------------------------------------------------+
Security Layers
Layer 1: Encryption at Rest
- Algorithm: AES-256-GCM (Authenticated Encryption)
- Key Derivation: PBKDF2 with 800,000 iterations (OWASP 2025 standard)
- Hash Function: SHA-256
- IV (Initialization Vector): 96 bits, randomly generated per encryption
- Salt: 256 bits (32 bytes), randomly generated per key
- Authentication Tag: 128 bits for integrity verification
Layer 2: Device Binding
- Purpose: Prevents encrypted keys from being copied to other machines or extension installations
- Implementation: Uses HKDF (HMAC-based Key Derivation Function) to combine:
- User-provided password
- Extension ID (unique per installation)
- Randomly generated device salt (stored locally)
- Result: Encrypted keys become device-specific and cannot be decrypted on different installations
Layer 3: Rate Limiting
- Max Attempts: 5 failed password attempts
- Lockout Strategy: Exponential backoff
- 1st lockout: 30 seconds
- 2nd lockout: 60 seconds
- 3rd lockout: 120 seconds
- Maximum lockout: 1 hour
- Attack Window: 15 minutes
- Storage: Rate limit state stored in
chrome.storage.session(cleared on browser close)
Layer 4: Session Caching
- Cache Duration: User-configurable from 5 minutes to 6 hours (default: 30 minutes)
- Inactivity Timeout: User-configurable from 5 to 60 minutes (default: 15 minutes)
- Session Persistence: Optional setting to keep session active when sidepanel closes (default: disabled)
- Storage:
chrome.storage.session(memory-only, cleared on browser close) - Access Level:
TRUSTED_CONTEXTS(not accessible to content scripts) - Additional Protection: Cached keys are encrypted with an ephemeral runtime key
Layer 5: Password Requirements
- Minimum Length: 12 characters
- Complexity: At least 3 of 4 character types (uppercase, lowercase, numbers, special)
- Validation:
- Common password rejection (dictionary check)
- Sequential pattern detection (e.g., "abcd", "1234")
- Excessive character repetition detection (e.g., "aaaa")
- Entropy: Minimum 72 bits recommended for API key protection
Security Features
Timing Attack Protection
All decryption operations enforce a minimum execution time of 400ms to prevent timing-based password guessing attacks, even when keys don't exist.
Error Message Safety
- No distinction between "key not found" and "wrong password" timing
- Generic error codes instead of detailed failure reasons
- No API key content in logs or error messages
External Communication Blocking
- All external messages from other extensions are blocked via
onMessageExternal - All external connections are blocked via
onConnectExternal - API key operations are never exposed externally
Session Management
- Uses
chrome.alarmsAPI for reliable timeout handling (survives service worker restarts) - Automatic session clearing on extension suspend
- SESSION_LOCKED messages notify UI when timeout occurs
- Configurable Settings: Session expiry (5 min to 6 hours), inactivity timeout (5 to 60 min)
- Validation Enforcement: Settings limits are enforced at multiple levels (UI, storage, retrieval)
Password Security
Validation Rules
- Length: 12-128 characters
- Character Types: Must contain at least 3 of:
- Uppercase letters (A-Z)
- Lowercase letters (a-z)
- Numbers (0-9)
- Special characters (!@#$%^&*)
- Quality Checks:
- Not in common password list
- No more than 3 consecutive identical characters
- No sequential patterns (keyboard walks, alphabetical sequences)
Password Strength Scoring
| Score Range | Rating | Description |
|---|---|---|
| 0-29 | Weak | Does not meet minimum requirements |
| 30-49 | Fair | Meets minimum but could be stronger |
| 50-69 | Good | Strong password |
| 70-100 | Strong | Excellent password |
API Key Validation
Supported Providers
| Provider | Format | Validation |
|---|---|---|
| OpenAI | sk-*, sk-proj-*, sk-svcacct-* |
Regex pattern matching |
| Anthropic | sk-ant-* |
Strict pattern matching |
| OpenRouter | sk-or-v1-* |
64-character suffix verification |
Display Masking
API keys are masked when displayed: sk-pro********abc1
- Shows first 6 characters
- Shows last 4 characters
- Masks middle with 8 asterisks
Content Security Policy
The extension enforces strict CSP to prevent injection attacks:
script-src 'self'; // Only allow scripts from extension
object-src 'none'; // Block plugins
base-uri 'none'; // Prevent base tag hijacking
connect-src 'self' [APIs]; // Restrict network requests
form-action 'none'; // Prevent form submissions
frame-ancestors 'none'; // Prevent framing
Cryptographic Implementation
Encryption Process
- Generate random 256-bit salt
- Generate random 96-bit IV
- Derive encryption key using PBKDF2:
- Input: compound password (user password + device secret)
- Salt: random salt
- Iterations: 800,000
- Hash: SHA-256
- Output: 256-bit AES key
- Encrypt plaintext using AES-256-GCM
- Combine:
salt || iv || ciphertext || auth_tag - Encode as base64 for storage
Decryption Process
- Decode base64 ciphertext
- Extract: salt, IV, ciphertext, auth tag
- Derive decryption key using same PBKDF2 parameters
- Decrypt and verify authentication tag
- Return plaintext or throw DECRYPTION_ERROR
Threat Model & Mitigations
Threat: Brute Force Password Attack
- 800,000 PBKDF2 iterations (computationally expensive)
- Rate limiting with exponential backoff
- Account lockout after 5 attempts
Threat: Timing Attacks
- Minimum 400ms operation time for all decryption attempts
- Constant-time comparisons where possible
- PBKDF2 naturally normalizes timing
Threat: Key Extraction (Physical Access)
- Device binding prevents cross-machine usage
- Keys never stored in plaintext
- Session cache cleared on browser close
Threat: Extension Reinstallation
- New device salt generated on reinstall
- Old keys become unrecoverable (by design)
- User warnings about data loss
Threat: Content Script Injection
- Session storage set to TRUSTED_CONTEXTS only
- External messaging blocked
- Strict CSP prevents code injection
Threat: Man-in-the-Middle (API Calls)
- All API endpoints use HTTPS (enforced by CSP)
- Host permissions restricted to specific domains
Compliance & Standards
This implementation follows:
- OWASP 2024/2025 cryptographic recommendations
- NIST SP 800-132 password-based key derivation guidelines
- Chrome Extension MV3 security best practices
- OWASP Top 10 vulnerability prevention
Security Audit Checklist
- AES-256-GCM with 128-bit authentication tag
- PBKDF2 with 800,000 iterations
- Random IV generation (96 bits)
- Random salt generation (256 bits)
- HKDF for device binding
- Rate limiting with exponential backoff
- Session timeout (configurable: 5 min to 6 hours, default 30 min)
- Inactivity timeout (configurable: 5 to 60 min, default 15 min)
- Session persistence with encrypted key storage
- Multi-level validation enforcement (UI, storage, retrieval)
- 6-hour maximum limit with security warning
- Password strength validation
- Common password rejection
- Timing attack protection
- External message blocking
- Strict Content Security Policy
- TRUSTED_CONTEXTS session storage
- Ephemeral session key encryption
- Chrome alarms for timeout persistence
Known Limitations
- JavaScript Memory: Cannot guarantee secure memory clearing due to language limitations. Garbage collector may leave traces of decrypted keys in memory.
- Browser Extensions: Extension storage can be accessed by users with physical access to the machine through browser developer tools (though keys are encrypted).
- Key Recovery: If a user forgets their password, there is no recovery mechanism. This is by design - no backdoors.
- Device Reinstall: Reinstalling the extension makes old encrypted keys permanently unrecoverable.
- Session Persistence Trade-off: When session persistence is enabled, the ephemeral session key is stored (encrypted) in session storage rather than memory-only. While still protected by encryption and device binding, this slightly reduces security in exchange for convenience.
Reporting Security Issues
If you discover a security vulnerability in this implementation, please report it via:
- GitHub Security Advisories
Please do not disclose security issues publicly until they have been addressed.
References
- OWASP Key Management Cheat Sheet
- NIST SP 800-132: Recommendation for Password-Based Key Derivation
- Chrome Extension Security Best Practices
- Web Crypto API Documentation
While this extension implements industry-standard cryptographic practices and follows OWASP 2024/2025 security guidelines, no security system is completely infallible. By using this extension to store API keys, you acknowledge and accept the inherent security risks. You are solely responsible for choosing strong passwords, maintaining secure computing environments, monitoring API key usage, and rotating API keys regularly.