Skip to content

Commit 7fa7f8d

Browse files
committed
Replace execSync calls with execFileSync to avoid shell interpolation issues
- Shell Command String Interpolation (execSync) in Git Utilities • Locations: • replace_commit_symbol • handle_commit_item • select_files_of_commit_command • check_command_exists • Description: • These functions invoke execSync(\git show ${commit_hash}`)(using a shell) rather thanexecFileSync('git', ['show', commit_hash]). Currently commit_hashis constrained to hex characters by regex orgit logoutput, andcmdincheck_command_existscomes from the staticCLI_AGENTS` array, so it is not directly exploitable today, but shell interpolation is fragile if upstream callers change. • Remediation: • Standardize on execFileSync('git', [...]) without a shell across all Git helpers. └── apps └── editor └── src ├── commands │ └── select-files-of-commit-command.ts ├── extension.ts ├── features │ └── agentic-search │ └── agentic-search.ts ├── utils │ └── agentic-cli-invocation │ ├── agents │ │ ├── antigravity.ts │ │ ├── claude.ts │ │ ├── codex.ts │ │ ├── cursor.ts │ │ ├── grok.ts │ │ ├── index.ts │ │ └── opencode.ts │ ├── invoke-agentic-cli.ts │ └── utils │ └── check-command-exists.ts └── views ├── prompt │ └── backend │ ├── message-handlers │ │ ├── handle-preview-commit-symbol.ts │ │ └── utils │ │ ├── build-cli-prompt.ts │ │ └── build-prompt-payload.ts │ ├── prompt-view-provider.ts │ └── utils │ └── symbols │ ├── git │ │ └── replace-git-symbols.ts │ └── replace-symbols.ts └── shared └── utils └── hash-sign-quick-pick ├── hash-sign-quick-pick.ts └── symbols ├── commit-symbol.ts └── index.ts
1 parent 7f16cbb commit 7fa7f8d

4 files changed

Lines changed: 76 additions & 36 deletions

File tree

‎apps/editor/src/commands/select-files-of-commit-command.ts‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { execSync, execFileSync } from 'child_process'
1+
import { execFileSync } from 'child_process'
22
import * as fs from 'fs'
33
import * as path from 'path'
44
import * as vscode from 'vscode'
@@ -32,8 +32,13 @@ export const select_files_of_commit_command = (
3232
let last_selected_commit_hash: string | undefined
3333

3434
while (true) {
35-
const log_output = execSync(
36-
`git log --since="${GIT_LOG_SINCE_DURATION}" --pretty=format:"%H|%s|%ar"`,
35+
const log_output = execFileSync(
36+
'git',
37+
[
38+
'log',
39+
`--since=${GIT_LOG_SINCE_DURATION}`,
40+
'--pretty=format:%H|%s|%ar'
41+
],
3742
{
3843
cwd: repository.rootUri.fsPath,
3944
encoding: 'utf-8'
@@ -150,10 +155,14 @@ export const select_files_of_commit_command = (
150155
if (selected_commit.hash == 'ahead-of-branch') {
151156
let branches_output: string = ''
152157
try {
153-
branches_output = execSync(`git branch --sort=-committerdate`, {
154-
cwd: repository.rootUri.fsPath,
155-
encoding: 'utf-8'
156-
})
158+
branches_output = execFileSync(
159+
'git',
160+
['branch', '--sort=-committerdate'],
161+
{
162+
cwd: repository.rootUri.fsPath,
163+
encoding: 'utf-8'
164+
}
165+
)
157166
.toString()
158167
.trim()
159168
} catch (e) {
@@ -264,8 +273,14 @@ export const select_files_of_commit_command = (
264273
}
265274
} else {
266275
try {
267-
files_output = execSync(
268-
`git show --name-only --pretty="format:%B" ${selected_commit.hash}`,
276+
files_output = execFileSync(
277+
'git',
278+
[
279+
'show',
280+
'--name-only',
281+
'--pretty=format:%B',
282+
selected_commit.hash
283+
],
269284
{
270285
cwd: repository.rootUri.fsPath,
271286
encoding: 'utf-8'

‎apps/editor/src/utils/agentic-cli-invocation/utils/check-command-exists.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { execSync } from 'child_process'
1+
import { execFileSync } from 'child_process'
22
import * as os from 'os'
33

44
export const check_command_exists = (cmd: string): boolean => {
55
try {
66
const is_windows = os.platform() == 'win32'
7-
execSync(`${is_windows ? 'where' : 'command -v'} ${cmd}`, {
7+
execFileSync(is_windows ? 'where' : 'which', [cmd], {
88
stdio: 'ignore'
99
})
1010
return true

‎apps/editor/src/views/prompt/backend/utils/symbols/git/replace-git-symbols.ts‎

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as vscode from 'vscode'
2-
import { execSync, execFileSync } from 'child_process'
2+
import { execFileSync } from 'child_process'
33
import { get_git_repository } from '@/utils/git-repository-utils'
44
import { is_valid_git_branch_name } from '@/utils/is-valid-git-branch-name'
55
import { AsciiTree } from '@/utils/ascii-tree/ascii-tree'
@@ -208,8 +208,9 @@ export const replace_changes_symbol = async (params: {
208208

209209
let cache_key = full_match
210210
try {
211-
const head_sha = execSync('git rev-parse HEAD', {
212-
cwd: target_folder.uri.fsPath
211+
const head_sha = execFileSync('git', ['rev-parse', 'HEAD'], {
212+
cwd: target_folder.uri.fsPath,
213+
encoding: 'utf-8'
213214
})
214215
.toString()
215216
.trim()
@@ -231,9 +232,14 @@ export const replace_changes_symbol = async (params: {
231232
}
232233
}
233234

234-
const current_branch = execSync('git rev-parse --abbrev-ref HEAD', {
235-
cwd: target_folder.uri.fsPath
236-
})
235+
const current_branch = execFileSync(
236+
'git',
237+
['rev-parse', '--abbrev-ref', 'HEAD'],
238+
{
239+
cwd: target_folder.uri.fsPath,
240+
encoding: 'utf-8'
241+
}
242+
)
237243
.toString()
238244
.trim()
239245

@@ -349,8 +355,9 @@ export const replace_changes_symbol = async (params: {
349355

350356
let cache_key = full_match
351357
try {
352-
const head_sha = execSync('git rev-parse HEAD', {
353-
cwd: repository.rootUri.fsPath
358+
const head_sha = execFileSync('git', ['rev-parse', 'HEAD'], {
359+
cwd: repository.rootUri.fsPath,
360+
encoding: 'utf-8'
354361
})
355362
.toString()
356363
.trim()
@@ -372,9 +379,14 @@ export const replace_changes_symbol = async (params: {
372379
}
373380
}
374381

375-
const current_branch = execSync('git rev-parse --abbrev-ref HEAD', {
376-
cwd: repository.rootUri.fsPath
377-
})
382+
const current_branch = execFileSync(
383+
'git',
384+
['rev-parse', '--abbrev-ref', 'HEAD'],
385+
{
386+
cwd: repository.rootUri.fsPath,
387+
encoding: 'utf-8'
388+
}
389+
)
378390
.toString()
379391
.trim()
380392

@@ -602,10 +614,14 @@ export const replace_commit_symbol = async (params: {
602614

603615
let commit_message_body = ''
604616
try {
605-
const raw_msg = execSync(`git show -s --format=%B ${commit_hash}`, {
606-
cwd: target_folder.uri.fsPath,
607-
encoding: 'utf-8'
608-
}).toString()
617+
const raw_msg = execFileSync(
618+
'git',
619+
['show', '-s', '--format=%B', commit_hash],
620+
{
621+
cwd: target_folder.uri.fsPath,
622+
encoding: 'utf-8'
623+
}
624+
).toString()
609625
commit_message_body = AsciiTree.strip_from_text(raw_msg)
610626
} catch (error) {
611627
Logger.warn({
@@ -626,7 +642,7 @@ export const replace_commit_symbol = async (params: {
626642
.replace(/^-|-$/g, '')
627643

628644
if (symbol_type === 'Commit') {
629-
const diff = execSync(`git show ${commit_hash}`, {
645+
const diff = execFileSync('git', ['show', commit_hash], {
630646
cwd: target_folder.uri.fsPath,
631647
encoding: 'utf-8'
632648
}).toString()

‎apps/editor/src/views/shared/utils/hash-sign-quick-pick/symbols/commit-symbol.ts‎

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as vscode from 'vscode'
2-
import { execSync } from 'child_process'
2+
import { execFileSync } from 'child_process'
33
import {
44
LAST_SELECTED_REPOSITORY_IN_SYMBOLS_QUCK_PICK_STATE_KEY,
55
LAST_SELECTED_COMMIT_REFERENCE_ACTION_STATE_KEY
@@ -26,7 +26,7 @@ export const handle_commit_item = async (
2626
const git_folders: vscode.WorkspaceFolder[] = []
2727
for (const folder of workspace_folders) {
2828
try {
29-
execSync('git rev-parse --is-inside-work-tree', {
29+
execFileSync('git', ['rev-parse', '--is-inside-work-tree'], {
3030
cwd: folder.uri.fsPath,
3131
stdio: 'ignore'
3232
})
@@ -111,8 +111,13 @@ export const handle_commit_item = async (
111111
return 'continue'
112112
}
113113

114-
const log_output = execSync(
115-
`git log --pretty=format:"%H%n%s%n%cr" --since="${GIT_LOG_SINCE_DURATION}"`,
114+
const log_output = execFileSync(
115+
'git',
116+
[
117+
'log',
118+
'--pretty=format:%H%n%s%n%cr',
119+
`--since=${GIT_LOG_SINCE_DURATION}`
120+
],
116121
{
117122
encoding: 'utf-8',
118123
cwd: selected_folder.uri.fsPath
@@ -208,10 +213,14 @@ export const handle_commit_item = async (
208213

209214
try {
210215
let commit_message = ''
211-
const raw_msg = execSync(`git show -s --format=%B ${commit_hash}`, {
212-
cwd: selected_folder.uri.fsPath,
213-
encoding: 'utf-8'
214-
}).toString()
216+
const raw_msg = execFileSync(
217+
'git',
218+
['show', '-s', '--format=%B', commit_hash],
219+
{
220+
cwd: selected_folder.uri.fsPath,
221+
encoding: 'utf-8'
222+
}
223+
).toString()
215224
commit_message = AsciiTree.strip_from_text(raw_msg)
216225

217226
if (commit_message) {
@@ -220,7 +229,7 @@ export const handle_commit_item = async (
220229
)
221230
}
222231

223-
const diff = execSync(`git show ${commit_hash}`, {
232+
const diff = execFileSync('git', ['show', commit_hash], {
224233
cwd: selected_folder.uri.fsPath,
225234
encoding: 'utf-8'
226235
}).toString()

0 commit comments

Comments
 (0)