← Back to PRs

#16958: fix(security): escape user input in HTML gallery to prevent stored XSS

by CornBrother0x open 2026-02-15 08:36 View on GitHub →
size: M
## Summary - **Problem:** `write_gallery()` in the OpenAI image gen skill embeds user-provided prompt text, filenames, and output paths directly into HTML without escaping - **Why it matters:** Stored XSS — an attacker injects `<script>` tags via image prompts that execute when anyone opens the gallery (CVSS 7.5, CWE-79) - **What changed:** Applied `html.escape()` (Python stdlib) to all three user-controlled values before HTML embedding - **What did NOT change:** Gallery layout, image generation, file structure unchanged Closes #12538 ## Changes **`skills/openai-image-gen/scripts/gen.py`**: - Added `from html import escape as html_escape` - Escaped prompt text in `<figcaption>`, filename in `href`/`src` attributes, output path in `<code>` tag **`skills/openai-image-gen/scripts/test_gen.py`** (new): - 4 tests: XSS payloads, attribute injection, special characters, normal operation ## Security Impact - No new permissions, network calls, or execution surface changes - Fixes stored XSS vulnerability in generated HTML output ## Testing All 4 tests pass. Verified `<script>alert("xss")</script>` in prompt renders as escaped text, not executable JS. ## Compatibility Backward compatible. Special characters in prompts now display as HTML entities — no visual difference for normal text. ## AI Disclosure AI-assisted (Claude via OpenClaw). Code reviewed and tested. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes two security vulnerabilities across two skill scripts: - **Stored XSS in `gen.py`**: Applied `html.escape()` to user-controlled prompt text, filenames, and output paths before embedding them in the generated HTML gallery, preventing script injection via crafted image prompts (CWE-79). - **Symlink/path traversal in `package_skill.py`**: Added symlink rejection and resolved-path boundary checks during `.skill` file creation, preventing sensitive file exfiltration via symlink attacks or crafted path traversal (zip-slip). Both fixes are minimal, targeted, and backward compatible. New test files cover the security scenarios for each fix. <h3>Confidence Score: 4/5</h3> - This PR is safe to merge — it adds targeted security hardening with no functional behavior changes. - Both security fixes are correct and well-scoped. The HTML escaping uses Python's stdlib `html.escape()` with appropriate `quote=True` for attribute contexts. The symlink/path traversal protection uses a defense-in-depth approach (symlink check + resolved path boundary check). New tests cover the key attack vectors. Only minor style issues (unused imports in test files) were found. - No files require special attention. Both fixes are straightforward and well-tested. <sub>Last reviewed commit: 055d8de</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs