4037b582757f86eed1c5559eca9ccc7af85c1496 braney Fri Aug 21 10:00:49 2026 -0700 lib: add htmlSanitize, an allowlist filter for HTML written elsewhere, refs #38126 htmlSanitize() takes a piece of HTML and returns a copy holding only the elements, attributes and style properties on its lists. An element on the keep list survives with its allowed attributes. A short list of elements that carry nothing for a reader, script and style and form among them, is dropped along with its contents. Every other element loses its tag and keeps its text, so a whole document that somebody saved and pasted in comes out as the article it was meant to be. The lists come from a survey of all 5390 description pages reachable from the public hub list, so they are sized to what hubs actually write. The style attribute is filtered a property at a time, and href and src are checked for a scheme we do not print, after decoding entities and padding. An iframe is kept only when it plays a video from one of a few hosts, and then with a sandbox attribute. htmlSanitizeReport() returns the same copy plus a list of one-line messages naming what came out, for hubCheck to show a hub author. The tokenizer is hand written and forgiving. It never aborts and always returns something, because the HTML it will be handed is often broken. lib/htmlPage.c cannot be reused for this: its parser aborts on bad input. diff --git src/lib/tests/htmlSanitizeTest.c src/lib/tests/htmlSanitizeTest.c new file mode 100644 index 00000000000..7f9f10b1605 --- /dev/null +++ src/lib/tests/htmlSanitizeTest.c @@ -0,0 +1,63 @@ +/* htmlSanitizeTest - check that htmlSanitize keeps what it should and drops the rest. */ + +/* Copyright (C) 2026 The Regents of the University of California + * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ + +#include "common.h" +#include "htmlSanitize.h" + +static char *cases[] = { +/* a whole pasted document comes out as the article it was meant to be */ +"
Text
", +/* script and style go, with their contents */ +"before
after
", +/* a script that is never closed takes the rest with it */ +"before