You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
One undecryptable secret aborts the entire secrets listing (passwords are not fail-soft) #620
get_user_secrets, search_user_secrets and get_user_secrets_with_shared decrypt the password (and recovery codes) with a bare public.decrypt_text inside a set-returning query. decrypt_text RAISES on an undecryptable value - a wrong key after a partial key rotation, storage corruption, or (with the v2 envelope) an HMAC mismatch - and one raised row aborts the WHOLE query. The user then sees every one of their secrets fail to load, not just the one bad row.
twofa_secret is already read through safe_decrypt_twofa_secret (NULL on failure); recovery codes and passwords are not - in the current RPCs both use raw decrypt_text, so both share this exposure. The same class of failure also aborts the backfill/rotation paths, but those are operator-run and fail closed by design; the listing is user-facing and should degrade per-row.
Suggested: add a try_decrypt_text(text) that returns NULL instead of raising (mirroring safe_decrypt_recovery_codes returning []), and route the password read through it and the recovery-codes read through safe_decrypt_recovery_codes in all three listing RPCs, so one corrupt row surfaces as a single blanked field while every other secret still loads. Do not name it safe_decrypt_* - the key-rotation script treats every such function as a mapped bespoke-format adapter and refuses to run if one is unmapped.
Claiming this issue with #652. The submission hardens all three listing RPCs, preserves the non-null desktop password contract, and adds regression coverage for corrupt owned and directly shared rows.
Verified fixed on current dev: migration 20260914010000_fail_soft_secret_listing_decryption.sql (merged via #668, integrated via #695) adds try_decrypt_text and routes get_user_secrets, search_user_secrets, and get_user_secrets_with_shared through COALESCE(try_decrypt_text(...), empty string), with recovery codes via safe_decrypt_recovery_codes. Regression coverage runs in the Database pgTAP job: supabase/tests/fail_soft_secret_listing_decryption_test.sql pins corrupt-row listing alongside healthy rows, blanked password, and error-class propagation. Closable as fixed by #668/#695.
Activity
akashjadon04 commentedon Sep 14, 2026
Claiming this issue with #652. The submission hardens all three listing RPCs, preserves the non-null desktop password contract, and adds regression coverage for corrupt owned and directly shared rows.
Mihir-Rabari commentedon Sep 22, 2026
Verified fixed on current dev: migration 20260914010000_fail_soft_secret_listing_decryption.sql (merged via #668, integrated via #695) adds try_decrypt_text and routes get_user_secrets, search_user_secrets, and get_user_secrets_with_shared through COALESCE(try_decrypt_text(...), empty string), with recovery codes via safe_decrypt_recovery_codes. Regression coverage runs in the Database pgTAP job: supabase/tests/fail_soft_secret_listing_decryption_test.sql pins corrupt-row listing alongside healthy rows, blanked password, and error-class propagation. Closable as fixed by #668/#695.