Stored XSS via [innerHTML] of feedback comment in feedback-details dialog
The feedback-details dialog renders `feedback` via Angular `[innerHTML]`; the value is the `feedback.comment` field passed from the administration component already wrapped in `bypassSecurityTrustHtml`, executing attacker-controlled HTML in the admin's browser when a row is clicked.
feedback-details.component.html L17-19:
<div class="feedback-content">
<cite [innerHTML]="feedback"></cite>
</div>
feedback-details.component.ts L26-29:
ngOnInit (): void {
this.feedback = this.dialogData.feedback
this.id = this.dialogData.id
}
The dialog is opened from administration.component.ts L124-131 with feedback: feedback.comment, where feedback.comment was previously passed through DomSanitizer.bypassSecurityTrustHtml (L91). The original comment originates from user-submitted feedback (POST /api/Feedbacks) where the only server-side defence is sanitize-html based and intentionally bypassable.
Same payload as the administration feedback XSS (e.g., <img src=x onerror=alert(1)> via a sanitize-html bypass, or, with the legacy challenge sanitizer enabled, <<script>script>...</script>). Submit via POST /api/Feedbacks, then as admin open the administration page and click the row to open the details dialog — the [innerHTML] sink renders the trusted HTML.
Persistent XSS reachable from the admin UI, executing in the administrator's browser.
The template at line 18 binds user-derived content to [innerHTML] on a <cite> element. The feedback value comes from dialogData.feedback, which is set in administration.component.ts to feedback.comment after it has been wrapped with DomSanitizer.bypassSecurityTrustHtml, disabling Angular's built-in HTML sanitization. Since the comment originates from untrusted user input (POST /api/Feedbacks) and the server-side sanitize-html has documented bypasses, an attacker-stored payload (e.g., <iframe src="javascript:..."> or sanitizer bypass) executes in the admin's browser when the row is opened. The exploit chain (submit feedback → admin opens dialog → innerHTML renders trusted HTML) is intact.
The payload is delivered via the public POST /api/Feedbacks endpoint (no auth required for the injection step) and is later rendered through [innerHTML]="feedback" after being wrapped in bypassSecurityTrustHtml, so any HTML/JS the attacker submits executes verbatim in the administrator's browser when they open the feedback-details dialog. AV:N because the attack is over the web; AC:L because only a known sanitize-html bypass payload is needed; PR:N because the submission step is anonymous; UI:R because an admin must click the feedback row to open the dialog. Scope is Changed because the JS executes in the privileged admin's origin/session rather than the attacker's own context, yielding full confidentiality and integrity impact over admin-accessible data and actions (session theft, admin-only API calls); availability is not meaningfully affected.
- CWE-79
- OWASP Top 10 A03:2021