A Qt/SQLite history table encrypts its path columns and matches rows by re-encrypting the paths. The update had three independent faults, each one hiding the next. A store-update-load test found them, and a negative test kept the fix from dropping the match rule.
Three takes on storing sensitive data in a database you don't control: AES-256-CTR fields in a desktop app's SQLite, an encrypted payload with an HMAC in MongoDB documents, and a drop-in encrypted text field for SQLAlchemy and Django.