refactor: improve type guard for domUtils.isNode#1000
Conversation
- Change isNode to return a type predicate (value is HTMLElement) - Remove unnecessary type assertions in code using isNode - Simplify type narrowing in SvgCanvas2D, XmlCanvas2D, TooltipHandler, and TextShape
|
|
||
| if (!isNode(val)) { | ||
| val = `<div><div>${this.convertHtml(val as string)}</div></div>`; | ||
| val = `<div><div>${this.convertHtml(val)}</div></div>`; |
Check warning
Code scanning / CodeQL
Unsafe HTML constructed from library input Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 months ago
In general, to fix this class of problems you must either (a) sanitize/escape any HTML you construct from library inputs before inserting it into the DOM, or (b) change the API so that callers provide structured elements instead of raw HTML strings, or (c) clearly document that the function only accepts trusted HTML. Since this is a low-level rendering helper and we should not rely on all callers correctly treating inputs as trusted, the safe approach is to ensure that whatever is inserted into the DOM cannot execute arbitrary scripts.
The single best fix here is to sanitize the result of convertHtml before using it to construct the HTML wrapper string in createDiv. The project already imports htmlEntities from ../../util/StringUtils.js, which suggests it is an escaping helper for HTML. We can apply htmlEntities to the converted HTML string, then place that escaped string inside our wrapper DIVs. That way, any <script> tags or other markup in user-controlled input will be rendered as literal text rather than being interpreted as HTML, while still preserving the current behavior of convertHtml for well-formed inputs. Concretely, in createDiv, instead of:
if (!isNode(val)) {
val = `<div><div>${this.convertHtml(val)}</div></div>`;
}we transform the inner string via htmlEntities:
if (!isNode(val)) {
const safeHtml = htmlEntities(this.convertHtml(val as string));
val = `<div><div>${safeHtml}</div></div>`;
}We already have htmlEntities imported at the top of SvgCanvas2D.ts, so no new imports are required. This change localizes the fix to the tainted data flow identified by CodeQL and addresses all alert variants that stem from unsafe HTML reaching div.innerHTML and the nested nodes/foreignObject created from it.
| @@ -1114,7 +1114,8 @@ | ||
| let val = str; | ||
|
|
||
| if (!isNode(val)) { | ||
| val = `<div><div>${this.convertHtml(val)}</div></div>`; | ||
| const safeHtml = htmlEntities(this.convertHtml(val as string)); | ||
| val = `<div><div>${safeHtml}</div></div>`; | ||
| } | ||
|
|
||
| if (document.createElementNS) { |
There was a problem hiding this comment.
These is a valuable feedback.
This is out of the scope of the PR, and will be managed by #1022
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/util/domUtils.ts (1)
225-231:⚠️ Potential issue | 🟠 MajorType guard is narrower than runtime behavior.
isNodeaccepts any Element (including SVGElement) at runtime but the predicate narrows toHTMLElement, creating a type soundness issue. Widen the predicate toElementto match the actual runtime check.Suggested fix
export const isNode = ( value: any, nodeName: string | null = null, attributeName?: string | null, attributeValue?: string | null -): value is HTMLElement => { +): value is Element => {
|
|
Converted to draft to check feedback from #1000 (review) |




Summary by CodeRabbit