GHSA-26wg-9xf2-q495 Novu has a XSS sanitization bypass

Not scored Published

Incomplete HTML sanitization in Novu allows attackers to inject malicious scripts via email previews, potentially leading to account takeover.

Exploited in the wild
Not known
Login needed
Any signed-in user
Attackable
Over the internet
Victim action needed
A user has to click or open something
Fix
Available

What is GHSA-26wg-9xf2-q495?

GHSA-26wg-9xf2-q495 is a cross-site scripting vulnerability in novu/api, published on 14 Apr 2026. Any signed-in user can exploit it over the network, and only if a user opens a file or follows a link.

Official description

Summary

XSS sanitization is incomplete, some attributes are missing such as oncontentvisibilityautostatechange=. This allows for the email preview to render HTML that executes arbitrary JavaScript,

Details

Sanitization is implemented here: https://github.com/novuhq/novu/blob/next/libs/application-generic/src/services/sanitize/sanitizer.service.ts

With allowedAttributes: false, all attributes are allowed through sanitize-html. Even dangerous ones like oncontentvisibilityautostatechange=. The DANGEROUS_ATTRIBUTES array tries to handle this by denying more attributes after the fact, but this list is incomplete. I copied all well-known payloads from: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet And found that the oncontentvisibilityautostatechange= attribute isn't detected.

PS. there seems to also be another even more lax sanitizer here, but I wasn't able to figure out where it is used: https://github.com/novuhq/novu/blob/next/packages/framework/src/utils/sanitize.utils.ts

PoC

  1. Create a new workflow and add an Email step
  2. In the body, write the following HTML code:
<a oncontentvisibilityautostatechange="alert(window.origin)" style="display:block;content-visibility:auto">
  1. Wait a second and notice the XSS popup showing the current origin:

<img width="1515" height="610" alt="image" src="https://github.com/user-attachments/assets/7d519a50-3bed-4f04-b78c-9c5938717433" />

https://dashboard.novu.co/env/dev_env_gVtdgDEhgf1CetwX/workflows/onboarding-demo-workflow_wf_gVtdh2uV0h7j3ffK/steps/email-step_st_gVtqdgIrOkYVvP9F/editor

Impact

This may look like a Self-XSS similar to https://github.com/novuhq/novu/security/advisories/GHSA-w8vm-jx29-52fr, but it can be more impactful. First of all, if multiple users can access this dashboard, the link above can directly bring the to the email step editor to trigger the XSS. An attacker can also use the Google/GitHub OAuth flows without completing the code callback step, and send that URL to the victim to intentionally log the vicitm into the attacker's account. If the attacker has prepared an XSS payload there, they will now be allowed to view it, so it triggers.

Which versions are affected by GHSA-26wg-9xf2-q495?

2 open source packages ship an affected version, including novu/api.

PackageAffectedFixed in
novu/api npmAll versions3.15.0
novu/api npmAll versions3.15.0

How do I fix GHSA-26wg-9xf2-q495?

Upgrade novu/api to 3.15.0 or later.

Escape output for the context it lands in and set a strict Content Security Policy. Upgrading the affected component is the real fix. More about Cross-site scripting.

Is GHSA-26wg-9xf2-q495 being exploited?

There is no known exploitation of GHSA-26wg-9xf2-q495 in the wild and no public exploit code.

Sources

Is GHSA-26wg-9xf2-q495 in your software?

Upload an SBOM and sbomify checks it against every vulnerability here, every day.

Check your SBOMs for free