diff --git a/.jules/sentinel.md b/.jules/sentinel.md index e5a3dcc..f925480 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -9,3 +9,8 @@ **Vulnerability:** Missing input length limits on snippets and projects, leading to potential client-side DoS or memory exhaustion. **Learning:** In a client-side application where all data is kept in memory (and localStorage), excessively large inputs can degrade performance or crash the browser. Input validation must happen at both the UI level and during data ingestion (imports). **Prevention:** Implement `maxLength` on all user-facing inputs and enforce the same limits in JSON parsing/import logic to ensure data stays within safe bounds. + +## 2025-05-16 - Defense in Depth for Master Password Requirements +**Vulnerability:** Weak master password requirements (8 characters) below modern security standards for cryptographic applications. +**Learning:** Enforcing password strength in the UI is necessary for user experience, but must be complemented by enforcement at the cryptographic layer to prevent bypass. Centralizing these limits in a `LIMITS` object ensures consistency across the application. +**Prevention:** Always use a centralized `LIMITS` constant for security-critical thresholds and implement validation in both the UI components and the core logic (e.g., crypto functions). diff --git a/components/EncryptionModal.jsx b/components/EncryptionModal.jsx index b5a72c0..e176990 100644 --- a/components/EncryptionModal.jsx +++ b/components/EncryptionModal.jsx @@ -4,7 +4,6 @@ import React, { useState } from 'react'; import { Lock, Shield, ShieldOff, Eye, EyeOff, AlertTriangle, Key } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { MASTER_PASSWORD_MAX_LENGTH } from '@/lib/constants'; import { Dialog, DialogContent, @@ -16,6 +15,19 @@ import { import { cn } from '@/lib/utils'; import { LIMITS } from '@/lib/constants'; +// Helper to validate password strength +const validatePassword = (pw) => { + if (pw.length < LIMITS.MASTER_PASSWORD_MIN) { + return `Password must be at least ${LIMITS.MASTER_PASSWORD_MIN} characters`; + } + // Require at least 4 unique characters to prevent simple repetition like "123123123123" + const uniqueChars = new Set(pw).size; + if (uniqueChars < 4) { + return 'Password is too simple. Use a wider variety of characters.'; + } + return null; +}; + // Setup encryption for first time export function EncryptionSetupModal({ open, onClose, onSetup }) { const [password, setPassword] = useState(''); @@ -27,8 +39,9 @@ export function EncryptionSetupModal({ open, onClose, onSetup }) { const handleSetup = async () => { setError(''); - if (password.length < 8) { - setError('Password must be at least 8 characters'); + const validationError = validatePassword(password); + if (validationError) { + setError(validationError); return; } @@ -75,7 +88,7 @@ export function EncryptionSetupModal({ open, onClose, onSetup }) {