CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-25049

Git-R-Done: RCE in n8n via Config Injection

Alon Barad
Alon Barad
Software Engineer

Feb 5, 2026·7 min read·112 visits

Executive Summary (TL;DR)

n8n interprets strings in double curly braces as code. By crafting a malicious `.git/config` file (e.g., in a repo cloned by n8n), an attacker can inject JavaScript payloads. When the Git node lists the config, n8n evaluates the payload, leading to full RCE.

A critical Remote Code Execution (RCE) vulnerability in n8n's Git node allows authenticated users to execute arbitrary commands via malicious Git configuration values. This creates a classic sandbox escape scenario where data is treated as code.

The Hook: Low-Code, High-Risk

We love low-code platforms. They empower marketing teams to build complex automations without bothering the engineering department. But there's a dark side to this democratization of logic: the abstraction layer. Under the hood, platforms like n8n are essentially massive, always-on evaluation engines that take input from one place, treat it like a magical template, and shove it into another place.

In this episode of "Why We Can't Have Nice Things," we are looking at CVE-2026-25049, a critical RCE in n8n. The vulnerability lies in the Git Node. This component is designed to help you manage version control within your workflows—pulling repos, pushing changes, and listing configurations. It sounds innocent enough.

However, n8n has a feature—or a bug, depending on who you ask—called "Expression Evaluation." Anything wrapped in {{ }} is treated as JavaScript and executed. The problem arises when the platform trusts external data sources to not contain these magic delimiters. Spoiler alert: Git config files are just text files, and they definitely shouldn't be trusted.

The Flaw: A Tale of Two Evals

To understand this exploit, you have to understand how n8n processes data. When a node runs, it outputs JSON. When the next node runs, it can reference that JSON. If you drag-and-drop a value in the n8n UI, it creates an expression like {{ $node["Git"].json["remote.origin.url"] }}.

The vulnerability is a classic case of Improper Control of Dynamically-Managed Code Resources (CWE-913), specifically Expression Injection. The Git node's "List Config" operation reads the .git/config file, parses the INI format, and spits out a JSON object containing keys like remote.origin.url.

Here is the logic flaw: The Git node didn't sanitize the values it read from disk. It just passed them along as strings. If an attacker controls the git repository (or can inject into the config), they can set the URL to something like https://{{require('child_process').execSync('calc')}}@github.com.

When the Git node runs, it successfully reads that string. It's just text. But the moment a subsequent node references that value, the n8n expression engine wakes up. It sees the curly braces, assumes it's a template meant for it, and executes the JavaScript code inside. It's a delayed-trigger landmine.

The Code: The Smoking Gun

Let's look at the implementation. The vulnerability existed in packages/nodes-base/nodes/Git/GenericFunctions.ts. The code was blindly trusting the output of the git command.

The Vulnerable Logic

Before the patch, the code essentially did this (simplified):

// Pseudocode of the vulnerability
const config = await git.listConfig();
return config.all; // Returns raw strings containing {{...}}

The Fix

In commit 78608969 (and follow-up 936c06cf), the developers realized that allowing raw strings from a config file to pass through to the expression engine was a bad idea. They introduced a sanitizeUrl function.

> [!NOTE] > The fix relies on the JavaScript URL constructor. By parsing the string as a URL object and then stringifying it back, special characters like { and } are percent-encoded (e.g., %7B).

Here is the essence of the patch:

// The mitigation strategy
const sanitizeUrl = (url: string) => {
	try {
		const urlObj = new URL(url);
		urlObj.password = ''; // Also strips creds, nice bonus
		urlObj.username = '';
		return urlObj.toString(); // Returns encoded string
	} catch (error) {
		return url;
	}
};

While this stops the remote.origin.url vector, it feels like a game of Whac-A-Mole. If the attacker finds a config value that isn't run through this sanitizer but is displayed by the node, the game is back on.

The Exploit: Escaping the Sandbox

Exploiting this requires a bit of setup, but it's devastatingly reliable. We need to trick n8n into processing a Git config file we control. This could happen if the workflow clones a public repository we own, or if we have partial access to the system.

The Attack Chain

  1. Preparation: Create a malicious git repository. Modify the .git/config file to include a Node.js payload in a standard field.
  2. The Payload: We use the require('child_process') primitive, which is available in the n8n execution environment.
[remote "origin"]
    url = https://{{require('child_process').execSync('cat /etc/passwd').toString()}}@github.com/evil/repo.git
  1. The Trigger: In n8n, create a workflow with a Git Node set to List Config. Connect it to a Debug Node (or any node that references the output).
  2. Execution: When the Debug node tries to resolve {{ $json["remote.origin.url"] }}, the engine parses the inner injection.

The result isn't just a string; it's the output of the command. You have effectively turned a configuration reader into a webshell.

The Research: Bypassing the Fix

As a researcher, looking at the patch (Commit 936c06cf), I see a potential logical gap. The patch explicitly applies sanitizeUrl to remote.origin.url and remote.origin.pushurl.

// Selective sanitization?
if (config.values['remote.origin.url']) {
    config.values['remote.origin.url'] = sanitizeUrl(config.values['remote.origin.url']);
}

However, Git config files are flexible. What about remote.upstream.url? What about submodule.name.url? Or even standard fields like user.email? If the Git node outputs all keys found in the config file using a spread operator or a loop, and only sanitizes the "known bad" ones, the vulnerability persists.

If I were attacking a "patched" version, I would immediately fuzz other Git configuration keys. If n8n displays user.name and I set my git username to {{require('fs').writeFileSync(...)}}, I might still achieve RCE. This selective patching strategy is often fragile against creative attackers.

The Impact: Why You Should Care

This is a CVSS 9.4 for a reason. n8n is often the "brain" of an organization's operations. It holds API keys for Stripe, Slack, AWS, CRMs, and databases.

If an attacker gains RCE on the n8n host:

  1. Credential Theft: They can dump the n8n database or environment variables to steal every connected API key.
  2. Lateral Movement: n8n usually sits inside the internal network to talk to internal databases. The host becomes a pivot point.
  3. Supply Chain Poisoning: The attacker can modify other workflows to inject malicious logic into business processes (e.g., "When a new invoice is created, send a copy to my email").

This isn't just "I hacked a server." It's "I hacked your business logic."

Mitigation: Stopping the Bleeding

The immediate fix is obvious: Update. n8n versions 1.123.17 and 2.5.2 include the patch. But let's look at defense-in-depth, because relying on a regex-based URL sanitizer is risky business.

Strategic Defense

  1. Isolate Execution: Run n8n in a strictly sandboxed container. Do not mount the host Docker socket (/var/run/docker.sock) unless absolutely necessary. If you do, an RCE in n8n is root on the host.
  2. Least Privilege: The user running the n8n process should not have access to sensitive system files.
  3. Sanitize Inputs: If you are automating Git operations, ensure the repositories you clone are trusted. Don't let your marketing automation clone arbitrary URLs provided by external users.

For the developers out there: Stop using eval (or its moral equivalents) on data you didn't create. If you must have a template engine, ensure the context allows strictly for data substitution, not arbitrary code execution.

Official Patches

n8nOfficial GitHub Security Advisory

Fix Analysis (2)

Technical Appendix

CVSS Score
9.4/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

Affected Systems

n8n workflow automation tool

Affected Versions Detail

Product
Affected Versions
Fixed Version
n8n
n8n-io
< 1.123.171.123.17
n8n
n8n-io
< 2.5.22.5.2
AttributeDetail
CWE IDCWE-913
Attack VectorNetwork
CVSS Score9.4 (Critical)
ImpactRemote Code Execution (RCE)
Vulnerable ComponentGit Node (List Config operation)
Exploit ComplexityLow

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-913
Expression Injection

Improper Control of Dynamically-Managed Code Resources

Known Exploits & Detection

Context AnalysisInjection of Node.js require('child_process') calls via .git/config URL fields.

Vulnerability Timeline

Patch commits pushed to repository
2026-01-23
CVE-2026-25049 Published
2026-02-04
GHSA Advisory Released
2026-02-04

References & Sources

  • [1]GHSA-6cqr-8cfr-67f8 Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•CVE-2026-63188
8.7

CVE-2026-63188: Unauthenticated Directory Traversal in @logto/tunnel

A high-severity path traversal vulnerability exists in the @logto/tunnel npm package (part of the Logto repository) prior to version 0.3.9. Remote unauthenticated attackers can exploit this vulnerability to read arbitrary local files by sending crafted HTTP requests with directory traversal sequences when the static file proxy is active.

Alon Barad
Alon Barad
2 views•7 min read
•about 7 hours ago•CVE-2026-54347
8.7

CVE-2026-54347: Stored Cross-Site Scripting in Froxlor DNS TXT Record Configuration

A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.

Amit Schendel
Amit Schendel
3 views•6 min read
•about 8 hours ago•CVE-2026-54348
7.2

CVE-2026-54348: Second-Order SQL Injection in Froxlor API Layer

An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 9 hours ago•CVE-2026-54543
5.4

CVE-2026-54543: DNS Resource Record (RR) Injection in Froxlor DomainZones API

CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.

Amit Schendel
Amit Schendel
4 views•7 min read
•about 10 hours ago•CVE-2026-42533
9.2

CVE-2026-42533: NGINX Map Directive and Regex Matching Pre-Auth Heap Buffer Overflow & Info Leak

CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.

Alon Barad
Alon Barad
7 views•7 min read
•about 10 hours ago•CVE-2026-55593
6.5

CVE-2026-55593: Persistent Administrative Hijacking via Cross-Site Request Forgery in Froxlor Ajax Router

Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.

Amit Schendel
Amit Schendel
6 views•8 min read