T09 · Insecure Skill Coding Practices
- Location
scripts/visual_renderer.py:233- Finding
Unsanitized Meal Names Are Injected into Chromium-Rendered HTML
- Content
View full analysis
{"".join([f'' for n,k in items[:5]])} ``` The resulting HTML is subsequently passed to Chromium through `html2image`: ```python hti = Html2Image(output_path=BASE_DIR) hti.screenshot(html_str=html, save_as="daily_report_raw.png", size=(1200, 900)) ``` ### Technical Analysis Meal names originate from user-controlled CLI input and are stored in SQLite without HTML validation: ```python c.execute("INSERT INTO entries (date, food_name, calories, protein, photo_path) VALUES (?, ?, ?, ?, ?)", (date, food_name, calories, protein, photo_path)) ``` The renderer retrieves these values and interpolates each meal name, represented by `n`, directly into an HTML document. No context-appropriate HTML escaping is applied before the document is loaded by Chromium. A meal name containing elements such as `{n}{k} kcal`, ``, SVG, or other browser-supported markup can therefore modify the generated document. Depending on Chromium and `html2image` runtime restrictions, injected markup may cause requests to arbitrary remote or local-network URLs. It can also conceal or falsify nutrition information in the generated report. The bundled food database does not contain malicious markup. The exploitable input path instead comes from arbitrary meal names accepted by the `add` command and potentially from names returned by the optional USDA API. ### Attack Path 1. An attacker supplies or induces the user to log a crafted meal name, for example: ```bash python3 scripts/calorie_visualizer.py add '<img src="https://attacker.example/track">' 100 5 ``` 2. `add_entry()` stores the crafted name in `calorie_data.db`. 3. A successful l ...[truncated 1158 chars]
- Remediation
View remediation
' f'{html.escape(str(name), quote=True)}' f'{html.escape(str(calories), quote=True)} kcal' f'' for name, calories in items[:5] ) ``` 2. Insert the pre-escaped `food_items_html` into the template instead of constructing markup from raw database values. 3. Apply strict length and character validation to meal names at ingestion, while retaining HTML escaping as the primary defense. 4. Treat names returned by online APIs as untrusted and escape them identically. 5. Configure the Chromium renderer to disable network access during report generation if supported. 6. Consider rendering the report without a browser, using a graphics library that treats meal names only as text. 7. Add regression tests using names containing `<`, `>`, `"`, `'`, SVG, `iframe`, and remote-resource elements, and verify that they appear as literal text without causing network requests. ]]>
