Stored XSS: blog body HTML is sanitized with bypassable regex. (found via S1135 TODO triage)
BlogContentValidator.SanitizeHtmlBody (SpikerSoft.Business/Domain/Blog/Validation) is applied to user-submitted request.Body in CreateBlogPostCommandHandler and UpdateBlogPostCommandHandler, then stored and rendered as blog HTML (the method deliberately allows 'safe HTML'). Its own comment flags the gap:
// TODO: In production, use HtmlSanitizer library for proper HTML sanitization
Why the current regex approach is exploitable (OWASP explicitly warns against regex HTML sanitization):
It removes only <script>...</script> PAIRS, inline on*= handlers, javascript: and data: substrings.
It strips no dangerous tags — <iframe>, <object>, <embed>, <svg>, <math>, <base>, <link>, <meta>, <form> all pass through. e.g. <iframe src="//evil">, <svg onload=...>, <math href=...>.
The javascript: filter is defeated by HTML-entity encoding the browser still decodes: <a href="javascript:alert(1)">.
Event-handler regex is defeated by whitespace/newline tricks and by re-introduction after a single non-recursive pass; mutation-XSS via malformed tags sidesteps regex entirely.
Impact: an authenticated blog author (or anyone who can reach these endpoints) can store markup that executes JavaScript in every viewer's browser (stored XSS) — session theft, CSRF-token exfiltration, account takeover of readers/admins.
Fix: replace the regex logic in SanitizeHtmlBody with a real allowlist-based sanitizer — the developer-intended HtmlSanitizer (Ganss.Xss), which parses the DOM (AngleSharp) and allowlists safe tags/attributes/URL schemes, defeating the above classes of bypass. Configure a blog-appropriate allowlist (headings, p, strong/em, lists, links with http/https/mailto only, blockquote, code/pre, img with http/https src). Keep the existing spam/link checks. Add XSS-bypass regression tests (iframe, svg/onload, entity-encoded javascript:, mutation vectors).
Severity: HIGH (stored XSS on a rendered content surface). SonarQube surfaced the TODO as csharpsquid:S1135; the underlying issue is the sanitizer design.
**Stored XSS: blog body HTML is sanitized with bypassable regex.** (found via S1135 TODO triage)
`BlogContentValidator.SanitizeHtmlBody` (SpikerSoft.Business/Domain/Blog/Validation) is applied to user-submitted `request.Body` in **CreateBlogPostCommandHandler** and **UpdateBlogPostCommandHandler**, then stored and rendered as blog HTML (the method deliberately allows 'safe HTML'). Its own comment flags the gap:
> // TODO: In production, use HtmlSanitizer library for proper HTML sanitization
**Why the current regex approach is exploitable** (OWASP explicitly warns against regex HTML sanitization):
- It removes only `<script>...</script>` PAIRS, inline `on*=` handlers, `javascript:` and `data:` substrings.
- It strips **no dangerous tags** — `<iframe>`, `<object>`, `<embed>`, `<svg>`, `<math>`, `<base>`, `<link>`, `<meta>`, `<form>` all pass through. e.g. `<iframe src="//evil">`, `<svg onload=...>`, `<math href=...>`.
- The `javascript:` filter is defeated by HTML-entity encoding the browser still decodes: `<a href="javascript:alert(1)">`.
- Event-handler regex is defeated by whitespace/newline tricks and by re-introduction after a single non-recursive pass; mutation-XSS via malformed tags sidesteps regex entirely.
**Impact:** an authenticated blog author (or anyone who can reach these endpoints) can store markup that executes JavaScript in every viewer's browser (stored XSS) — session theft, CSRF-token exfiltration, account takeover of readers/admins.
**Fix:** replace the regex logic in SanitizeHtmlBody with a real allowlist-based sanitizer — the developer-intended HtmlSanitizer (Ganss.Xss), which parses the DOM (AngleSharp) and allowlists safe tags/attributes/URL schemes, defeating the above classes of bypass. Configure a blog-appropriate allowlist (headings, p, strong/em, lists, links with http/https/mailto only, blockquote, code/pre, img with http/https src). Keep the existing spam/link checks. Add XSS-bypass regression tests (iframe, svg/onload, entity-encoded javascript:, mutation vectors).
Severity: HIGH (stored XSS on a rendered content surface). SonarQube surfaced the TODO as csharpsquid:S1135; the underlying issue is the sanitizer design.
Resolved in spikersoft-backend PR #373 (merged to master, reviewed by spikerj). Replaced the bypassable regex blog-body sanitization with the allowlist/DOM-based HtmlSanitizer (Ganss.Xss 9.0.892), restricted URL schemes to http/https/mailto, dropped interactive form controls, and added XSS-bypass regression tests (dangerous tags, svg onload, entity-encoded javascript:) plus a preserve-safe-formatting test. Closing.
Resolved in spikersoft-backend PR #373 (merged to master, reviewed by spikerj). Replaced the bypassable regex blog-body sanitization with the allowlist/DOM-based HtmlSanitizer (Ganss.Xss 9.0.892), restricted URL schemes to http/https/mailto, dropped interactive form controls, and added XSS-bypass regression tests (dangerous tags, svg onload, entity-encoded javascript:) plus a preserve-safe-formatting test. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Stored XSS: blog body HTML is sanitized with bypassable regex. (found via S1135 TODO triage)
BlogContentValidator.SanitizeHtmlBody(SpikerSoft.Business/Domain/Blog/Validation) is applied to user-submittedrequest.Bodyin CreateBlogPostCommandHandler and UpdateBlogPostCommandHandler, then stored and rendered as blog HTML (the method deliberately allows 'safe HTML'). Its own comment flags the gap:Why the current regex approach is exploitable (OWASP explicitly warns against regex HTML sanitization):
<script>...</script>PAIRS, inlineon*=handlers,javascript:anddata:substrings.<iframe>,<object>,<embed>,<svg>,<math>,<base>,<link>,<meta>,<form>all pass through. e.g.<iframe src="//evil">,<svg onload=...>,<math href=...>.javascript:filter is defeated by HTML-entity encoding the browser still decodes:<a href="javascript:alert(1)">.Impact: an authenticated blog author (or anyone who can reach these endpoints) can store markup that executes JavaScript in every viewer's browser (stored XSS) — session theft, CSRF-token exfiltration, account takeover of readers/admins.
Fix: replace the regex logic in SanitizeHtmlBody with a real allowlist-based sanitizer — the developer-intended HtmlSanitizer (Ganss.Xss), which parses the DOM (AngleSharp) and allowlists safe tags/attributes/URL schemes, defeating the above classes of bypass. Configure a blog-appropriate allowlist (headings, p, strong/em, lists, links with http/https/mailto only, blockquote, code/pre, img with http/https src). Keep the existing spam/link checks. Add XSS-bypass regression tests (iframe, svg/onload, entity-encoded javascript:, mutation vectors).
Severity: HIGH (stored XSS on a rendered content surface). SonarQube surfaced the TODO as csharpsquid:S1135; the underlying issue is the sanitizer design.
Resolved in spikersoft-backend PR #373 (merged to master, reviewed by spikerj). Replaced the bypassable regex blog-body sanitization with the allowlist/DOM-based HtmlSanitizer (Ganss.Xss 9.0.892), restricted URL schemes to http/https/mailto, dropped interactive form controls, and added XSS-bypass regression tests (dangerous tags, svg onload, entity-encoded javascript:) plus a preserve-safe-formatting test. Closing.