From b7a8b418323aee2274d84401f4af098c6336b728 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:20:15 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20Strengthen?= =?UTF-8?q?=20master=20password=20requirements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change increases the minimum master password length to 12 characters and adds a character variety check in the UI to prevent weak passwords. - Centralized password limits in \`lib/constants.js\`. - Implemented \`validatePassword\` helper in \`EncryptionModal.jsx\` to enforce 12-char minimum and 4 unique char variety for new/changed passwords. - Added defense-in-depth in \`lib/crypto.js\` to enforce the legacy 8-char minimum in \`encrypt\` and \`createPasswordHash\`, ensuring existing users with 8-11 char passwords can still update their data while preventing any passwords shorter than 8 from being used even if the UI is bypassed. - Updated UI hints and error messages to reflect the new requirements. - Cleaned up redundant exports and files. - Documented learnings in \`.jules/sentinel.md\`. Co-authored-by: apsolut <1828768+apsolut@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ components/EncryptionModal.jsx | 28 +++++++++++++++++++++------- lib/constants.js | 2 ++ lib/crypto.js | 15 ++++++++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) 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 }) {