T09 · Insecure Skill Coding Practices
- Location
scripts/generate_pdf.py:26- Finding
Untrusted HTML Is Rendered with Active Browser Capabilities and No Execution Timeout
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_pdf.py, lines 26–33
Vulnerability Type: Unsafe processing of potentially untrusted active HTML
Risk Level: MediumVulnerable Code
python subprocess.run([ CHROME, "--headless", "--disable-gpu", f"--print-to-pdf={pdf}", "--no-pdf-header-footer", url, ], check=True, capture_output=True)Technical Analysis
The PDF generator opens the supplied HTML file in a full headless Chrome process without disabling JavaScript, blocking network access, applying a restrictive Content Security Policy, or imposing an execution timeout.
Although the command is constructed as an argument array and is therefore not directly vulnerable to shell command injection, HTML is active content. A crafted document can contain JavaScript, remote resource references, automatic navigation, or requests to services reachable from the machine running the skill.
The skill workflow in
SKILL.mdinstructs the agent to generate HTML from user-provided source material and immediately pass that HTML to this script. If attacker-controlled markup is preserved or inserted into the generated document, the active content executes when Chrome renders the PDF.The absence of a timeout also allows hostile HTML to consume CPU or keep the renderer occupied indefinitely through expensive scripts, pathological layouts, repeated navigation, or continuously loading resources.
Attack Path
- An attacker supplies a crafted HTML file directly to
generate_pdf.py, or provides source material designed to cause active markup to appear in the generated report. - The skill invokes
generate_pdf.pyas required by its standard workflow. - The script converts the local path to a
file://URL and opens it in headless Chrome. - Chrome executes embedded JavaScript and attempts attacker-selected network requests using the host's network connectivity.
- The ...[truncated 1566 chars]
- An attacker supplies a crafted HTML file directly to
- Remediation
View remediation
Remediation Suggestions
-
Sanitize generated HTML before rendering
- Parse output with an allowlist-based HTML sanitizer.
- Remove
script,iframe,object,embed,form, and active metadata elements. - Remove event-handler attributes such as
onclickandonerror. - Reject
javascript:URLs and unnecessary remote resource references.
-
Disable JavaScript
- Render through a dedicated Chrome profile configured with JavaScript disabled.
- Alternatively, use a renderer designed for static HTML-to-PDF conversion that does not execute scripts.
-
Block network access during conversion
- Run Chrome in a container or sandbox namespace with no outbound network connectivity.
- Deny loopback, link-local, private, and metadata-service address ranges.
- Ensure the report is fully self-contained before rendering.
-
Apply a restrictive Content Security Policy
- Inject a policy equivalent to
default-src 'none'; style-src 'unsafe-inline'; img-src data:; font-src data:where document requirements permit. - Do not rely on CSP as the only control; combine it with sanitization and network isolation.
- Inject a policy equivalent to
-
Add resource and time limits
- Pass a finite
timeouttosubprocess.run. - Catch
subprocess.TimeoutExpired, terminate the Chrome process tree, remove incomplete output, and return a controlled error. - Enforce memory and CPU limits through an operating-system sandbox or container.
- Pass a finite
-
Validate inputs
- Require a regular file with an approved extension.
- Restrict input and output paths to explicitly authorized directories when the script is invoked by the skill.
- Reject symbolic links where they are not required.
-
Use an isolated temporary browser profile
- Start Chrome with a newly created, permission-restricted profile directory.
- Delete that profile after conversion.
- Do not reuse the operator's normal browser p ...[truncated 40 chars]
-
