diff --git a/docs/proposals/fix-1600-sec015-xhtml-findings.md b/docs/proposals/fix-1600-sec015-xhtml-findings.md
new file mode 100644
index 00000000..8f60c7d0
--- /dev/null
+++ b/docs/proposals/fix-1600-sec015-xhtml-findings.md
@@ -0,0 +1,120 @@
+# Fix 1600 SEC-015 x-html Security Info Findings
+
+**Date:** 2026-02-15
+**Status:** Planned
+**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**.