Skip to content

Instantly share code, notes, and snippets.

@JorianWoltjer
Last active November 21, 2024 07:55
Show Gist options
  • Save JorianWoltjer/75ea5431298ad5e7502c7e4af60ed67f to your computer and use it in GitHub Desktop.
Save JorianWoltjer/75ea5431298ad5e7502c7e4af60ed67f to your computer and use it in GitHub Desktop.
Mutation XSS Challenge (patched)
const { JSDOM } = require('jsdom');
const http = require("http");
function parseConsistent(html) {
let prevHtml = '';
for (let i = 0; i < 10; i++) {
// Parse until HTML is the same twice
dom = new JSDOM(html);
html = dom.window.document.body.innerHTML;
if (html === prevHtml) {
return dom;
}
prevHtml = html;
}
throw new Error('HTML is inconsistent');
}
function sanitize(html) {
if (html.length > 1000) {
throw new Error('HTML is too long');
}
const { document, NodeFilter } = parseConsistent(html).window;
// Remove comments
const nodeIterator = document.createNodeIterator(document.body, NodeFilter.SHOW_COMMENT);
while (nodeIterator.nextNode()) {
nodeIterator.referenceNode.remove();
}
// Remove dangerous text nodes
const dangerousTags = document.querySelectorAll(
'script, iframe, style, xmp, noembed, noframes, noscript, plaintext, template');
dangerousTags.forEach(tag => tag.remove());
// Remove all attributes
const allTags = document.querySelectorAll('*');
allTags.forEach(tag => {
const attributes = Array.from(tag.attributes);
attributes.forEach(attr => tag.removeAttribute(attr.name));
});
return document.body.innerHTML;
}
const server = http.createServer((req, res) => {
const params = new URLSearchParams(req.url.split('?')[1]);
const html = params.get('html') || '';
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(sanitize(html));
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server is running http://localhost:${PORT}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment