Encryption preserves bytes; it does not decide whether those bytes are safe to render later. A rich-text editor needs an explicit content-safety boundary before the browser encrypts and Rails loses the ability to inspect the protected payload.
Sanitization and encryption solve different problems
Sanitization constrains markup before it is rendered. Encryption protects confidentiality and integrity of a payload after it is created. One cannot stand in for the other: ciphertext that later decrypts to unsafe markup is still unsafe markup.
For an encrypted editor, the distinction is practical. Once Rails receives ciphertext, it cannot safely parse the original HTML to repair an unsafe tag without becoming part of the decryption boundary.
The useful order is sanitize, then encrypt
editor HTML
→ sanitize with DOMPurify
→ serialize approved markup
→ encrypt with the unlocked Master Key
→ submit ciphertext to Rails
Inpages.me follows this order for encrypted rich-text content. It also preserves the visible editor while autosave transforms a FormData copy, so the user is not left looking at ciphertext after a save.
Keep the protected set explicit
For an encrypted Memory, the protected set includes the title, rich-text content, external-link text and URLs, keepsake bytes, and inline-image bytes. Some operational metadata is outside that set. The implementation must say which fields are transformed instead of using encryption as an imprecise label.
The browser encryption architecture lists the current boundary and its trade-offs in detail.
Decryption is not permission to trust HTML
When a vault unlocks, the client restores approved text into the editor. That path should preserve the same markup assumptions made at write time. A client-side sanitizer is not a license to interpolate arbitrary HTML elsewhere in the application, nor does it remove the need for standard output escaping outside the editor.
This is why the policy described in CSP nonces with Turbo is a useful second layer rather than an alternative to sanitizing content.
Do not move inspection to Rails by accident
Protected text is deliberately opaque to Rails. Server-side validation can still check identity ownership, request shape, and protection-state transitions, but it does not decrypt rich text to scan or normalize it. This preserves the privacy architecture while making the browser-side sanitizer a first-class part of the feature.
The corresponding state transition is covered in changing a live Memory to encrypted without partial state.
Test the boundary, not only the happy path
Useful tests cover a locked vault, a rejected protection transition, an encrypted autosave, and a page that rehydrates after local unlock. They should also assert that the server stores transformed data without invoking a decryption routine.
Our approach to these layers is expanded in testing browser-based encryption in Rails. The goal is evidence that the order is preserved when code changes, not a one-time demonstration.