T09 · Insecure Skill Coding Practices
- Location
scripts/render_briefing_package.py:16- Finding
Unescaped Template Substitution Enables HTML Injection
- Content
View full analysis
str: safe = template_text for key, value in replacements.items(): safe = safe.replace("{{" + key + "}}", value) return safe ``` Command-line values are placed directly into the replacement map: ```python replacements = { "title": args.title, "date": args.date, "audience": args.audience, "scope": args.scope, "summary_bullet_1": "[Add the most important development]", "summary_bullet_2": "[Add the second most important development]", "summary_bullet_3": "[Add the third most important development]", "story_1_headline": "[Insert lead headline]", "story_1_summary": "[Summarize the lead story in 2 to 4 sentences.]", "story_1_why": "[Explain why this matters now.]", "story_1_sources": "[Add source links]", "story_2_headline": "[Insert second headline]", "story_2_summary": "[Summarize the second story.]", "story_2_why": "[Explain the implication.]", "story_2_sources": "[Add source links]", "story_3_headline": "[Insert third headline]", "story_3_summary": "[Summarize the third story.]", "story_3_why": "[Explain the implication.]", "story_3_sources": "[Add source links]", "watch_item_1": "[Add watch item]", "watch_item_2": "[Add watch item]", "watch_item_3": "[Add watch item]", "closing_take": "[Write a concise closin ...[truncated 3219 chars]- Remediation
View remediation
dict[str, str]: return { key: escape(value, quote=True) for key, value in replacements.items() } ``` Use the escaped map only for HTML rendering: ```python html_replacements = build_html_replacements(replacements) write_file( output_dir / "briefing.html", render_with_placeholders( html_template, html_replacements, ).rstrip() + "\n", ) ``` 2. Keep separate replacement maps for Markdown and HTML. HTML escaping should not be applied indiscriminately to Markdown output because the two formats have different rendering requirements. 3. Prefer an established template engine with automatic HTML escaping, such as Jinja2 configured with `autoescape=True`, if additional templates or dynamic contexts are introduced. 4. Treat all future story text, source links, headlines, and watchlist content as untrusted. Escape element text and validate URL schemes separately before inserting links into `href` attributes. 5. Add regression tests using payloads containing: - Script elements. - Closing HTML tags. - Event-handler attributes. - Double and single quotation marks. - Ampersands and angle brackets. - `javascript:` URLs if dynamic hyperlink attributes are later supported. 6. Verify that generated HTML displays these test values as literal text and does not create additional DOM elements or executable event handlers. ]]>
