- seaglass (new module): bluemonday v1.0.27 policy ported from Journal without the Blog Editor rules, byte-stable token comparison, SanitizeReport, Sanitize, Check, Removals - cabana: type richeditor (common keys plus size); every create and update value sanitized before Fill, non-string values are a 422, removals become meta.notices; settings and relation forms refuse the type - backend lang richeditor.removed_* and markup_changed (en, pl plurals) - TestSeaglassSmoke, TestCompanionsRichEditorSmoke, README and docs
seaglass
HTML sanitizer for stored rich text: a bluemonday allowlist policy that returns clean HTML byte for byte and reports what it removed from the rest.
import "git.golem15.com/golem15/summercms/modules/seaglass"
Name: Glass the sea has worn smooth; rough HTML goes in and only the safe, smooth part comes out.
Overview
seaglass is the framework's one HTML policy for rich text an administrator stores, such as cabana's type: richeditor field. It wraps bluemonday v1.0.27 with the policy the Journal plugin uses for imported WinterCMS content, without that plugin's editor-specific rules. A tokenizing sanitizer checks attributes and URLs the way a browser parses them, so it does not share the bypasses of regex gates (<img src="x"onerror=…>, javascript:, <svg/onload=…>).
The comparison is byte-stable: when the input and the policy's output tokenize to the same HTML tokens, the input itself is returned, so a value that only differs in escaping is never rewritten. Otherwise the policy's output is returned with a report of the removed elements, attributes and comments, which cabana shows to the administrator as save notices.
Role in the framework
A leaf utility with no SummerCMS dependency. cabana runs every richeditor value through it on create and update, top level and inside repeater rows; plugins that serve stored HTML in a public API can run it again on output, for content that was imported without passing the admin save.
Use cases:
- Sanitize an HTML field on save and tell the editor what was removed.
- Check that stored HTML is already clean (
seaglass.Check), for example in an import report. - Sanitize HTML on output in a public API.
Features
- bluemonday's UGC policy with links kept as written (no
rel="nofollow"),tel:links next tohttp,https,mailtoand relative URLs, and theclass,dir, microdata, footnoteroleand inlinecolor,font-size,font-weightandtext-alignstyles imported WinterCMS content uses. - Everything else is removed:
script,style,iframe,object,embed,form,svg,math, comments, everyon*attribute,target,rel, and URLs with any other scheme. seaglass.SanitizeReportreturns HTML the policy keeps whole byte for byte with a zeroseaglass.Removals; a tag that repeats an attribute is always a change.seaglass.Removalsnames the removed elements and attributes (at most ten distinct names each, in first-seen order) and counts every removal and every removed comment.
Usage
clean, report := seaglass.SanitizeReport(`<p onclick="x()">Hi</p><script>alert(1)</script>`)
// clean == "<p>Hi</p>"
// report.Elements == []string{"script"}, report.Attributes == []string{"onclick"}
if err := seaglass.Check(stored); err != nil {
// stored HTML would change under the policy
}
API reference
| Identifier | Description |
|---|---|
seaglass.Sanitize |
Returns the HTML filtered through the policy: the input itself when the policy keeps all of it. |
seaglass.SanitizeReport |
seaglass.Sanitize with a seaglass.Removals report of what was removed; a zero report exactly when the input is returned. |
seaglass.Check |
Returns an error when the policy would change the HTML, nil when it keeps it whole. |
seaglass.Removals |
What was removed: Elements and Attributes (distinct names), ElementCount and AttributeCount (every removal), Comments, and Changed (the HTML differs from the input). |
Dependencies
- SummerCMS modules: none.
- Third-party:
github.com/microcosm-cc/bluemondayv1.0.27 (the policy; decision note.planning/notes/2026-10-11-framework-html-sanitizer-bluemonday.md),golang.org/x/net/html(the token comparison and the removal report). - Standard library:
errors,fmt,io,regexp,slices,strings.
Testing
go test ./modules/seaglass/...
The tests run in memory and need no external services.