fix(voyage): sanitize bodyHtml via DOMPurify in renderArtifact (1d3591d4)
This commit is contained in:
parent
6eaa230953
commit
c08bde0649
2 changed files with 24 additions and 1 deletions
|
|
@ -1248,6 +1248,13 @@ playground first-run shows a complete round-trip-able artifact.
|
||||||
// v4.3 Step 25 — strip unsafe HTML-comments before markdown-it sees them.
|
// v4.3 Step 25 — strip unsafe HTML-comments before markdown-it sees them.
|
||||||
var safeText = stripUnsafeComments(text || '');
|
var safeText = stripUnsafeComments(text || '');
|
||||||
var bodyHtml = md.render(safeText);
|
var bodyHtml = md.render(safeText);
|
||||||
|
// v4.3 Step 1 — defense in depth: sanitize bodyHtml via DOMPurify
|
||||||
|
// (finding 1d3591d4). Applied to bodyHtml ONLY — fmHtml uses our
|
||||||
|
// own escapeHtml() on capturedFrontmatter and intentional
|
||||||
|
// <details>/<summary> markup that DOMPurify would otherwise strip.
|
||||||
|
var safeBody = (typeof window !== 'undefined' && window.DOMPurify && typeof window.DOMPurify.sanitize === 'function')
|
||||||
|
? window.DOMPurify.sanitize(bodyHtml, { USE_PROFILES: { html: true } })
|
||||||
|
: escapeHtml(bodyHtml);
|
||||||
// Pre-render-then-wrap for <details>: prepend a folded frontmatter
|
// Pre-render-then-wrap for <details>: prepend a folded frontmatter
|
||||||
// <details> block at the top if the front-matter plugin captured one.
|
// <details> block at the top if the front-matter plugin captured one.
|
||||||
var fmHtml = '';
|
var fmHtml = '';
|
||||||
|
|
@ -1255,7 +1262,7 @@ playground first-run shows a complete round-trip-able artifact.
|
||||||
fmHtml = '<details><summary>Frontmatter</summary><pre><code>' +
|
fmHtml = '<details><summary>Frontmatter</summary><pre><code>' +
|
||||||
escapeHtml(capturedFrontmatter) + '</code></pre></details>';
|
escapeHtml(capturedFrontmatter) + '</code></pre></details>';
|
||||||
}
|
}
|
||||||
return fmHtml + bodyHtml;
|
return fmHtml + safeBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(s) {
|
function escapeHtml(s) {
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,22 @@ test('voyage-playground.html renderArtifact strips comments before md.render (v4
|
||||||
assert.ok(stripIdx > 0 && stripIdx < renderIdx, 'stripUnsafeComments must run before md.render');
|
assert.ok(stripIdx > 0 && stripIdx < renderIdx, 'stripUnsafeComments must run before md.render');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// v4.3 Step 1 — SC24-security defense in depth: renderArtifact bodyHtml is
|
||||||
|
// sanitized via DOMPurify before DOM injection (finding 1d3591d4).
|
||||||
|
test('voyage-playground.html renderArtifact sanitizes bodyHtml via DOMPurify (v4.3 Step 1, finding 1d3591d4)', () => {
|
||||||
|
const text = readFileSync(HTML, 'utf-8');
|
||||||
|
// The literal DOMPurify.sanitize(bodyHtml expression must be present.
|
||||||
|
assert.match(text, /DOMPurify\.sanitize\(bodyHtml/, 'DOMPurify.sanitize(bodyHtml call required in renderArtifact');
|
||||||
|
// USE_PROFILES: { html: true } must appear nearby (within the renderArtifact body)
|
||||||
|
const bodyStart = text.indexOf('function renderArtifact');
|
||||||
|
assert.ok(bodyStart > 0, 'renderArtifact() must exist');
|
||||||
|
const bodyEnd = text.indexOf('\n }', bodyStart);
|
||||||
|
const body = text.slice(bodyStart, bodyEnd + 1);
|
||||||
|
assert.match(body, /USE_PROFILES:\s*\{\s*html:\s*true\s*\}/, 'USE_PROFILES html:true profile required inside renderArtifact');
|
||||||
|
// Return must reference safeBody, not raw bodyHtml
|
||||||
|
assert.match(body, /return\s+fmHtml\s*\+\s*safeBody/, 'renderArtifact return must use safeBody');
|
||||||
|
});
|
||||||
|
|
||||||
// v4.3 Step 26 — path-traversal + symlink/dotfile filter.
|
// v4.3 Step 26 — path-traversal + symlink/dotfile filter.
|
||||||
test('voyage-playground.html declares isProjectPathSafe filter (v4.3 Step 26)', () => {
|
test('voyage-playground.html declares isProjectPathSafe filter (v4.3 Step 26)', () => {
|
||||||
const text = readFileSync(HTML, 'utf-8');
|
const text = readFileSync(HTML, 'utf-8');
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue