BraveCMS's contact form is publicly accessible without authentication. User-supplied message text is passed through PHP's nl2br() function, which converts newlines to <br> tags but does not escape HTML. The resulting string is then passed to a Blade email template using the unescaped {!! $msg !!} directive, allowing arbitrary HTML to be injected into the email delivered to the site administrator. Modern email clients do not execute JavaScript, but they do render HTML, making this a reliable vector for phishing attacks against the administrator via crafted login forms or fake security alerts embedded in what appears to be a legitimate contact notification.
Details
Summary
| Field |
Value |
| CVE ID |
CVE-2026-41576 |
| Advisory |
GHSA-x7cg-8grr-grvx |
| Severity |
High |
| CWE |
CWE-79 (HTML Injection) |
| Package |
BraveCMS-2.0 (PHP) |
| Affected |
2.0 |
| Patched |
None |
| Vulnerability |
HTML Injection in outbound admin email via unescaped nl2br() output |
| Impact |
Admin credential phishing via injected HTML in contact notification email |
The contact form at POST /contact accepts a message from any unauthenticated visitor and forwards it to the site administrator by email. The message is processed with nl2br() to convert line breaks, then embedded in the email body with {!! $msg !!}. Because nl2br() does not perform HTML encoding and the Blade directive explicitly bypasses escaping, any HTML tags included in the message are rendered verbatim in the administrator's email client. An attacker can use this to inject convincing phishing interfaces, credential harvesting forms, or spoofed system alerts directly into the admin's inbox.
How it works
The controller processes the contact message and passes it to the mail template without escaping:
// ContactController.php (vulnerable)
'msg' => nl2br($request->message), // converts \n to <br> but does not encode HTML
The email Blade template renders the value without encoding:
{{-- email template (vulnerable) --}}
{!! $msg !!}
nl2br() is not an encoding function. It inserts <br> tags at line breaks but leaves all other HTML characters intact. Combined with {!! !!}, the full message body, including any tags the attacker included, is written directly into the email HTML. The administrator receives an email that appears to come from the CMS contact system but contains arbitrary attacker-controlled markup.
Root Cause
Two independent failures combine to create the vulnerability. The first is the misuse of nl2br() as a sanitization step: it was designed to improve text display, not to prevent HTML injection, and it provides no protection against tags or attributes. The second is the use of {!! !!} in an email template that receives externally supplied content. Unlike an admin-facing template where the content can reasonably be assumed trusted, a contact form is a public unauthenticated input channel and must never be rendered unescaped.
Prerequisites
- No authentication is required. The contact form is publicly accessible.
- The administrator must open the email and interact with the injected content for credential theft to succeed, making this a user-interaction-required attack.
- A standard HTML-capable email client such as Gmail or Outlook Web is sufficient to render the injected markup.
Fix
Two changes are required together in ContactController.php. Apply e() to HTML-encode the message before passing it to nl2br(), then switch the template directive to the safe escaped form:
// ContactController.php (fixed)
// e() encodes HTML entities first; nl2br() then safely converts the encoded newlines to <br>
'msg' => nl2br(e($request->message)),
{{-- email template (fixed) --}}
{{-- Safe: output is already HTML-encoded; Blade escaping adds a second layer --}}
{!! $msg !!}
Note that after applying e() the string already contains encoded entities and safe <br> tags, so using {!! !!} is acceptable at that point since the encoding was applied upstream. Alternatively, if line-break rendering is not required, the simplest fix is:
// ContactController.php (simplest fix, no HTML in email at all)
'msg' => $request->message,
{{-- email template --}}
{{ $msg }}
Laravel's {{ }} directive calls htmlspecialchars() automatically, neutralizing all HTML injection regardless of what the controller passes.
Key Takeaways
nl2br() is not a security function. It inserts <br> tags at newlines and leaves all other HTML characters completely untouched. Using it as a sanitization step before unescaped rendering provides no protection whatsoever.
- Public input channels must never reach unescaped templates. The contact form requires no authentication, which means it is reachable by any internet user. Any data from an unauthenticated source must be treated as fully untrusted and encoded before rendering.
- HTML injection in email is a distinct and underrated threat. JavaScript-based XSS is often the focus of injection discussions, but email clients that block scripts still render HTML faithfully. A convincing phishing interface delivered through a trusted notification channel is often more effective than a standalone phishing page because it arrives in a context the administrator already trusts.
- The fix is one function call. Wrapping the input in
e() before passing it to nl2br() resolves the vulnerability entirely and requires no architectural change.