test: add XSS-prevention suite for utils/sanitize
8 tests locking in security-critical behavior of sanitizeCustomHtml / sanitizeText: script-content removal, event-handler stripping, javascript: link neutralization, anchor hardening (noreferrer/noopener/_blank), non-mxc <img> → link conversion, and the N100 <pre class> language-* restriction. Verified against actual sanitize-html behavior. Suite now 27 tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { sanitizeCustomHtml, sanitizeText } from './sanitize';
|
||||
|
||||
test('sanitizeText escapes HTML metacharacters', () => {
|
||||
assert.equal(sanitizeText('<script>'), '<script>');
|
||||
assert.equal(sanitizeText('a & b'), 'a & b');
|
||||
assert.equal(sanitizeText(`"'`), '"'');
|
||||
assert.equal(sanitizeText('plain text'), 'plain text');
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml removes <script> content', () => {
|
||||
const out = sanitizeCustomHtml('<script>alert(1)</script>hello');
|
||||
assert.ok(!out.includes('alert'));
|
||||
assert.ok(out.includes('hello'));
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml strips event-handler attributes', () => {
|
||||
const out = sanitizeCustomHtml('<b onclick="evil()">hi</b>');
|
||||
assert.ok(!out.includes('onclick'));
|
||||
assert.ok(out.includes('hi'));
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml drops disallowed tags, keeps allowed ones', () => {
|
||||
assert.ok(!sanitizeCustomHtml('<iframe src="x"></iframe>').includes('iframe'));
|
||||
assert.ok(sanitizeCustomHtml('<strong>bold</strong>').includes('<strong>'));
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml neutralizes javascript: links', () => {
|
||||
const out = sanitizeCustomHtml('<a href="javascript:alert(1)">x</a>');
|
||||
// eslint-disable-next-line no-script-url -- asserting the scheme was stripped
|
||||
assert.ok(!out.includes('javascript:'));
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml hardens anchors (noreferrer/noopener/_blank)', () => {
|
||||
const out = sanitizeCustomHtml('<a href="https://example.com">x</a>');
|
||||
assert.ok(out.includes('rel="noreferrer noopener"'));
|
||||
assert.ok(out.includes('target="_blank"'));
|
||||
});
|
||||
|
||||
test('sanitizeCustomHtml converts a non-mxc <img> into a link', () => {
|
||||
const out = sanitizeCustomHtml('<img src="https://evil.example/x.png" alt="pic">');
|
||||
assert.ok(!out.includes('<img'));
|
||||
assert.ok(out.includes('href="https://evil.example/x.png"'));
|
||||
});
|
||||
|
||||
test('N100: <pre> class is restricted to the language-* whitelist', () => {
|
||||
assert.ok(sanitizeCustomHtml('<pre class="language-js">x</pre>').includes('language-js'));
|
||||
assert.ok(
|
||||
!sanitizeCustomHtml('<pre class="evil-site-class">x</pre>').includes('evil-site-class'),
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user