Skip to content

Commit d119ec4

Browse files
committed
Prevent use of --upload-pack as a command in git.fetch to avoid potential accidental command execution.
1 parent e4ff627 commit d119ec4

File tree

3 files changed

+47
-4
lines changed

3 files changed

+47
-4
lines changed

.changeset/silent-dodos-deny.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"simple-git": minor
3+
---
4+
5+
Resolves potential command injection vulnerability by preventing use of `--upload-pack` in `git.fetch`

simple-git/src/lib/tasks/fetch.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,23 @@ import { FetchResult } from '../../../typings';
22
import { parseFetchResult } from '../parsers/parse-fetch';
33
import { StringTask } from '../types';
44

5-
export function fetchTask(remote: string, branch: string, customArgs: string[]): StringTask<FetchResult> {
5+
import { configurationErrorTask, EmptyTask } from './task';
6+
7+
function disallowedCommand(command: string) {
8+
return /^--upload-pack(=|$)/.test(command);
9+
}
10+
11+
export function fetchTask(remote: string, branch: string, customArgs: string[]): StringTask<FetchResult> | EmptyTask {
612
const commands = ['fetch', ...customArgs];
713
if (remote && branch) {
814
commands.push(remote, branch);
915
}
1016

17+
const banned = commands.find(disallowedCommand);
18+
if (banned) {
19+
return configurationErrorTask(`git.fetch: potential exploit argument blocked.`);
20+
}
21+
1122
return {
1223
commands,
1324
format: 'utf-8',

simple-git/test/unit/fetch.spec.ts

+30-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { assertExecutedCommands, closeWithSuccess, like, newSimpleGit } from './__fixtures__';
2-
import { SimpleGit } from "../../typings";
1+
import { promiseError } from '@kwsites/promise-result';
2+
import { assertExecutedCommands, assertGitError, closeWithSuccess, like, newSimpleGit } from './__fixtures__';
3+
import { SimpleGit } from '../../typings';
34

4-
describe('push', () => {
5+
describe('fetch', () => {
56
let git: SimpleGit;
67
let callback: jest.Mock;
78

@@ -58,4 +59,30 @@ describe('push', () => {
5859
assertExecutedCommands('fetch', '--all', '-v');
5960
});
6061

62+
63+
describe('failures', () => {
64+
65+
it('disallows upload-pack as remote/branch', async () => {
66+
const error = await promiseError(git.fetch('origin', '--upload-pack=touch ./foo'));
67+
68+
assertGitError(error, 'potential exploit argument blocked');
69+
});
70+
71+
it('disallows upload-pack as varargs', async () => {
72+
const error = await promiseError(git.fetch('origin', 'main', {
73+
'--upload-pack': 'touch ./foo'
74+
}));
75+
76+
assertGitError(error, 'potential exploit argument blocked');
77+
});
78+
79+
it('disallows upload-pack as varargs', async () => {
80+
const error = await promiseError(git.fetch('origin', 'main', [
81+
'--upload-pack', 'touch ./foo'
82+
]));
83+
84+
assertGitError(error, 'potential exploit argument blocked');
85+
});
86+
87+
})
6188
});

0 commit comments

Comments
 (0)