# Fix 1600 SEC-015 x-html Security Info Findings **Date:** 2026-02-15 **Completed:** 2026-02-16 **Status:** Implemented **Validator:** Security (`scripts/validate/validate_security.py`) ## Current State All 3 validators are at **0 errors, 0 warnings**: | Validator | Errors | Warnings | Info | |-----------|--------|----------|------| | Architecture | 0 | 0 | 0 | | Security | 0 | 0 | **1600** | | Performance | 0 | 0 | 1527 | All 1600 security info findings are **SEC-015** — Alpine.js `x-html` directives flagged as potential XSS vectors across **162 HTML template files**. ## Analysis ### Breakdown by category | Category | Count | Pattern | Risk | |----------|-------|---------|------| | `$icon()` helper | ~1570 (98%) | `x-html="$icon('name', 'classes')"` | **None** — static SVG icon registry | | App-controlled content | ~20 | `x-html="$store.upgrade.getUpgradeCardHTML()"` | **None** — internal JS methods | | Product/CMS content | ~10 | `x-html="product.description"` | **Low** — admin-authored content | ### Top files by finding count | File | Count | |------|-------| | `dev_tools/admin/components.html` | 150 | | `marketplace/store/letzshop.html` | 33 | | `dev_tools/admin/icons.html` | 27 | | `tenancy/admin/module-info.html` | 22 | | `marketplace/admin/partials/letzshop-orders-tab.html` | 22 | | `orders/store/invoices.html` | 21 | | `orders/storefront/order-detail.html` | 21 | | `shared/macros/storefront/search-bar.html` | 20 | | `shared/macros/storefront/star-rating.html` | 18 | | Other 153 files | ~1266 | ### SEC-015 rule definition (in `validate_security.py`) ```python # Line 242-256: Check for x-html with dynamic content for i, line in enumerate(lines, 1): if re.search(r'x-html="[^"]*\w', line) and "sanitized" not in line.lower(): if self._is_noqa_suppressed(line, "SEC-015"): continue self._add_violation( rule_id="SEC-015", rule_name="XSS prevention in templates", severity=Severity.INFO, ... message="x-html renders raw HTML - ensure content is safe", suggestion="Use x-text for text content or sanitize HTML", ) ``` ## Plan ### Phase 1: Teach validator to recognize safe `$icon()` patterns (~1570 findings) **File:** `scripts/validate/validate_security.py` (around line 242) Add an exception for `$icon(` calls before the `x-html` check. These render SVG icons from a static Alpine.js magic helper (`window.icons`) and never include user input. ```python # Before the x-html check, skip safe icon patterns if re.search(r'x-html="\$icon\(', line): continue ``` This single change eliminates ~98% of findings. ### Phase 2: Suppress remaining ~30 with `` The remaining x-html usages fall into two categories: **A. App-controlled JS methods (~20)** — internal Alpine store methods: - `$store.upgrade.getUpgradeCardHTML()` - `$store.upgrade.getLimitWarningHTML()` - `$store.upgrade.getUsageBarHTML()` - `getNotificationIcon(notif.type)` - `window.icons?.['{{ icon }}']` These are safe — the HTML is generated by our own JS, not user input. Suppress with ``. **B. Product/CMS content (~10)** — admin-authored rich text: - `product.description` - `product.short_description` - `product.warranty` - Demo product content These render content authored by store admins (trusted users). Suppress with `` and add a `` comment. ### Phase 3: Verify ```bash # Should show 0 errors, 0 warnings, 0 info python scripts/validate/validate_security.py # Ensure templates still render correctly python -c "from main import app; print('OK')" # Run full test suite python -m pytest tests/ app/modules/*/tests/ -q --timeout=60 ``` ## Execution estimate - Phase 1: 1 edit to validator (~5 min) - Phase 2: ~30 HTML template edits across ~15 files (~30 min) - Phase 3: Verification (~15 min) ## Goal All 3 validators at **0 errors, 0 warnings, 0 info**.