- signpost: activation refusals, host overrides, D-02 pattern layers incl. PatternFrom, ReferenceOptions depths - seaglass: removal report, bluemonday bypass corpus, Check - pact Option.Depth omitempty and the menu item type contracts; party activates menu item types after Register and before the first Boot - cabana: repeater compile and decode, dependsOn compile and recheck, richeditor keys and notices, reorder and singleton boot checks (Docker-free); repeater save, dependent recheck, richeditor save, reorder and singleton routes on Postgres; conformance cases for the documented 404, 409 and 422 answers of the new routes - admin: richeditor value contract, link popover, notices and chunk failure; repeater bounds, remove and reorder, collapsed rows; dependent dropdown states and last request wins; reorder announcements, partition switch and tree rules; SingletonForm spec - gate: required names in the go, admin and postgres stages
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.