T09 · Insecure Skill Coding Practices
- Location
scripts/cover.py:986- Finding
Unescaped Cover Metadata Enables HTML Injection and Unrestricted Resource Loading
- Content
View full analysis
{t["subtitle"]}' image_block = "" if img_url: image_block = f"""""" abstract_block = "" if t.get("abstract"): abstract_block = f"""Abstract: {t['abstract']}""" ``` The generated HTML is subsequently opened in a browser without request filtering: ```javascript const page = await browser.newPage(); const fileUrl = "file://" + path.resolve(inputFile); await page.goto(fileUrl); await page.waitForTimeout(waitMs); ``` Google Fonts are also loaded directly from token data at `scripts/cover.py:19-23`: ```python def _gfonts_import(t: dict) -> str: """Return a CSS @import for the document's Google Fonts, if available.""" url = t.get("gfonts_import", "") if url: return f"@import url('{url}');" return "" ``` ### Technical Analysis Cover metadata is inserted directly into HTML and CSS without contextual escaping. In particular: - `cover_image` is placed inside a double-quoted HTML attribute. - `abstract`, `subtitle`, `title`, and other metadata are inserted as raw HTML text. - Font URLs and design tokens are inserted into CSS without validation. - Playwright opens the result as a local `file:// ...[truncated 2588 chars]- Remediation
View remediation
{ const url = new URL(route.request().url()); if (url.protocol === "file:" && path.resolve(url.pathname).startsWith(approvedRenderDirectory)) { return route.continue(); } return route.abort(); }); ``` If external resources are necessary, add narrowly scoped exceptions after validating the destination. 5. Render with JavaScript disabled unless a cover template demonstrably requires it: ```javascript const context = await browser.newContext({ javaScriptEnabled: false }); const page = await context.newPage(); ``` 6. Replace live Google Fonts with locally bundled, reviewed font files. This makes rendering deterministic and avoids unnecessary network disclosure. 7. Validate CSS token formats: - Colors should match a strict hexadecimal-color expression. - Font names should come from an internal allowlist. - Reject control c ...[truncated 259 chars]
