Feb 27, 2026·6 min read·6 visits
The Zendesk Trigger node in n8n failed to verify webhook signatures, allowing anyone with the webhook URL to spoof events. Attackers could trigger workflows with fake data. The fix introduces HMAC verification, but users must manually toggle workflows to fetch the signing keys.
A critical oversight in the n8n Zendesk Trigger node allowed attackers to forge incoming webhooks, bypassing authentication completely. By ignoring the cryptographic signature provided by Zendesk, n8n accepted any HTTP POST request to the webhook URL as a legitimate event. This vulnerability highlights the dangers of implicit trust in webhook endpoints and requires a manual intervention—deactivating and reactivating workflows—even after patching.
Automation platforms like n8n are the glue of the modern internet. They take data from Service A (Zendesk), massage it, and shove it into Service B (Slack, Jira, Postgres). It's magic, until it's black magic.
The Zendesk Trigger node is designed to sit passively, waiting for Zendesk to shout "New Ticket!" or "Ticket Updated!" via a webhook. Webhooks are essentially public HTTP endpoints. Because they are public, the standard security model relies on a "shared secret" handshake. Zendesk signs the payload, and the receiver (n8n) checks the signature.
But what happens when the receiver is too polite to check credentials? You get GHSA-38C7-23HJ-2WGQ. In affected versions of n8n, the Zendesk Trigger node was operating on the "honor system." It assumed that if a request arrived at the specific UUID-generated URL, it must be from Zendesk. It’s the digital equivalent of unlocking your front door just because someone knocked.
Zendesk, being a responsible platform, includes a header in its webhook requests: X-Zendesk-Webhook-Signature. This is an HMAC-SHA256 hash of the timestamp and the request body, signed with a secret key known only to Zendesk and the integration owner.
The vulnerability here wasn't a complex buffer overflow or a heap grooming exploit. It was a simple logic omission. The code responsible for handling the incoming trigger looked something like this (conceptually):
Notice the missing step? It never validated the X-Zendesk-Webhook-Signature. The node blindly trusted the input. This falls under CWE-345 (Insufficient Verification of Data Authenticity). If an attacker guessed, leaked, or brute-forced the webhook URL—which is often just a UUID—they could send any JSON payload they wanted. n8n would happily ingest it and pass it down the pipeline as trusted data.
The patch, introduced in commit 3839e310bd4c3002c646c363d1411916fa195151, reveals exactly how the developers closed the hole. They had to introduce a mechanism to fetch the signing secret and then use it to validate requests.
First, they added a helper to compute the HMAC:
function verifySignature(signature: string, timestamp: string, body: string, secret: string): boolean {
const hmac = crypto.createHmac('sha256', secret);
const data = timestamp + body;
const digest = hmac.update(data).digest('base64');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}> [!NOTE]
> Notice the use of crypto.timingSafeEqual. This prevents timing attacks where an attacker could guess the signature byte-by-byte by measuring how long the comparison takes.
However, the most interesting part of the patch is the fail-open mechanism for backward compatibility. Look at this logic in the trigger handler:
// If we don't have a secret, we can't verify, so we let it through
// to avoid breaking existing workflows that haven't been reactivated.
if (!webhookSecret) {
return true;
}This is a critical nuance. The code only verifies the signature if webhookSecret exists in the workflow's static data. This secret is only fetched when the node is activated (setup). This means patching the software is not enough to stop the exploit. Old workflows remain vulnerable until manually reset.
Let's assume we are the attacker. Our goal is to trigger an internal business process defined in n8n. Perhaps the workflow creates a Jira ticket or sends a Slack message when a "High Priority" Zendesk ticket arrives.
Step 1: Reconnaissance
We need the webhook URL. These often leak in client-side code, GitHub repos, or browser history. They look like https://n8n.corp.com/webhook/5f8b9....
Step 2: Crafting the Payload We don't need to sign anything. We just need to match the JSON structure the workflow expects. A standard Zendesk payload might look like this:
{
"ticket": {
"id": 1337,
"priority": "urgent",
"subject": "URGENT: Refund $50,000 to Attacker",
"description": "Authorized by CEO."
}
}Step 3: Execution We send the request using standard tools. No complex headers required, just the content type.
curl -X POST https://n8n.target.com/webhook/uuid-1234-5678 \
-H "Content-Type: application/json" \
-d '{"ticket": {"id": 999, "priority": "urgent", "subject": "pwned"}}'The n8n instance processes this as a valid event. If the workflow has logic like if (ticket.priority === 'urgent') send_slack_alert(), that alert fires. If it has logic like update_database(), the database is corrupt.
Why is this severity only "Moderate" (5.0)? It comes down to the Attack Complexity (AC:H). The attacker needs the specific Webhook URL. Unlike a standard RCE where you hit the root domain, this requires knowledge of a GUID.
However, once that URL is known, the impact can be severe depending on the workflow logic:
It turns the automation platform into a proxy for the attacker, bypassing internal firewalls because the requests originate from the trusted n8n server.
To mitigate this, you must update n8n to version 1.123.18, 2.6.2, or higher. But as mentioned in the code analysis, updating is only half the battle.
The Critical Step: Manual Reactivation Because the fix logic is "fail-open" (to prevent breaking legacy setups), the node will only enforce signature verification if it has fetched the signing secret from Zendesk. This fetch happens during the node's activation phase.
When you reactivate, n8n makes an API call to Zendesk: GET /webhooks/{id}/signing_secret. It stores this secret. Only then does the verifySignature logic kick in. If you skip this step, you are still vulnerable, even on the latest version.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
n8n n8n | < 1.123.18 | 1.123.18 |
n8n n8n | >= 2.0.0, < 2.6.2 | 2.6.2 |
| Attribute | Detail |
|---|---|
| Attack Vector | Network (Webhook Endpoint) |
| CVSS | 5.0 (Moderate) |
| CWE | CWE-345 (Insufficient Verification) |
| Exploit Status | PoC Available |
| Complexity | High (Requires URL knowledge) |
| Privileges Required | None |