Repository navigation
Commit 55bd549
Assert what the escaper must guarantee, not one spelling of one tag
CodeQL opened a high-severity js/bad-tag-filter alert on the feed escaping
test: `assert.doesNotMatch(xml, /<script>/u)` does not match `<SCRIPT>`.
There is no vulnerability behind it. escapeXml works character by character
— every `<` becomes `<` whatever follows it — so an upper case tag is
escaped exactly like a lower case one. What CodeQL found was the test, and
it was right about that: an assertion that hunts for one spelling of one tag
name would have stayed green while a real tag-name filter let `<SCRIPT>`
through.
So the assertion now states the invariant the escaper actually owes us:
nothing an agent writes comes back out of a description as markup. Not one
tag name — not a single angle bracket. Because it never looks at a tag name,
the case question disappears rather than being answered.
Measured rather than assumed. Against output from a filter with exactly that
flaw — `<script>` escaped, `<SCRIPT>` passed through verbatim — the old
assertion passes and the new one fails. Attempting the same proof by
weakening escapeXml itself was refused by the sandbox, correctly; the
comparison was made against a constructed string instead, and rss.ts was
never left broken in the tree.
Two smaller things the strict equality caught while writing it: the channel
carries its own `<description>` ahead of every item, so the first match in
the document is the wrong one, and the seed now carries both cases so the
expected string has to spell out what escaping both of them produces.
Local proof: 228 D1 tests pass, npm run check reports 0 errors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>1 parent 775391a commit 55bd549
1 file changed
Lines changed: 29 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
296 | 296 | | |
297 | 297 | | |
298 | 298 | | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
299 | 309 | | |
| 310 | + | |
300 | 311 | | |
301 | 312 | | |
302 | 313 | | |
303 | | - | |
| 314 | + | |
304 | 315 | | |
305 | 316 | | |
306 | 317 | | |
307 | | - | |
308 | | - | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
309 | 335 | | |
310 | 336 | | |
311 | 337 | | |
| |||
0 commit comments