@NOVU/API · CVE-2026-125114 · Package
FIX → 3.15.0
Novu's conditions filter webhook sends POST requests to user-configured URLs without the SSRF validation that the HTTP Request workflow step applies. An attacker who can create workflows can make the server reach internal addresses such as cloud metadata endpoints and read the response data through the execution details API.
first public Apr 14, 2026 · 1 source
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Teams running Novu, or building on @novu/api, where users can configure workflow condition webhooks. The flaw lets a workflow author reach internal services and metadata endpoints from the server, so self-hosted deployments on cloud infrastructure carry the most risk. Deployments that only use trusted workflow authors and block egress to internal addresses carry less.
Not affected if managed-hosting, no-condition-webhooks, version-3.15.0-or-later
Who cares @novu/api, cloud-metadata, novu, self-hosted
@novu/api version in package.json or the lockfile; affected versions are below 3.15.0.169.254.169.254.Upgrade to 3.15.0
The conditions filter webhook at libs/application-generic/src/usecases/conditions-filter/conditions-filter.usecase.ts line 261 sends POST requests to user-configured URLs using raw axios.post() with no SSRF validation. The HTTP Request workflow step in the same codebase correctly uses validateUrlSsrf() which blocks private IP ranges. The conditions webhook was not included in this protection.
conditions-filter.usecase.ts line 261:
return await axios.post(child.webhookUrl, payload, config).then((response) => {
return response.data as Record<string, unknown>;
});
No call to validateUrlSsrf(). The webhookUrl comes from the workflow condition configuration with zero validation.
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
@novu/api: move to 3.15.0 or later.execute-http-request-step.usecase.ts line 130:
const ssrfValidationError = await validateUrlSsrf(url);
if (ssrfValidationError) {
// blocked
}
This function resolves DNS and checks against private ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16). It exists in the codebase but is not applied to the conditions webhook path.
http://169.254.169.254/latest/meta-data/iam/security-credentials/axios.post() to the metadata endpointFull-read SSRF. The response body is returned as Record<string, unknown> for condition evaluation and stored in the execution details raw field. The GET /execution-details API returns this data.
The POST method limits some metadata endpoints (GCP requires GET, Azure requires GET), but AWS IMDSv1 accepts POST and returns credentials. Internal services accepting POST are also reachable.
Extract validateUrlSsrf() to a shared utility and call it before the axios.post in conditions-filter.usecase.ts:
const ssrfError = await validateUrlSsrf(child.webhookUrl);
if (ssrfError) {
throw new Error('Webhook URL blocked by SSRF protection');
}
return await axios.post(child.webhookUrl, payload, config)...
GitHub Advisory Database, CC-BY 4.0. Posts quoted belong to their authors.