Summary
Code scanning (rule typescript:S4036) flags 5 open alerts where git is invoked by bare name ('git'), relying on PATH resolution instead of using an absolute/verified executable path. An attacker who controls PATH could substitute a malicious git binary.
Alerts:
src/git/hook.ts:47 — resolveGitPath() calls execFileSync('git', ['rev-parse', '--git-path', ...])
src/git/hook.ts:219 — runPostCommitHook() default calls execSync('git log -1 --pretty=%B', ...)
src/commands/batch.ts:69 — gitHasChanges() calls execSync('git diff --cached --quiet', ...)
src/commands/batch.ts:81 — gitHasChanges() calls execSync('git diff --quiet', ...)
src/commands/batch.ts:116 — gitCommit() calls spawnSync('git', ['commit', '-F', tmpFile], ...)
Expected behavior
All git invocations use a resolved, verified git executable path.
Actual behavior
The affected files call git by name, letting PATH decide which binary runs.
Suggested fix
src/git/diff.ts already resolves the git executable (getGitExecutable() + resolveGitExecutable()); that logic fixed the equivalent S4036 alerts in diff.ts (alerts #12–#19). Reuse it:
- Export
getGitExecutable() from src/git/diff.ts (or move it to a shared module) and call the resolved path in hook.ts and batch.ts.
src/commands/batch.ts operates on arbitrary repo cwds — pass cwd and pass the resolved executable to execSync/spawnSync.
- For
resolveGitPath() in hook.ts, switch from execSync('git ...') to the resolved executable.
Environment
- OS: all (alerts are platform-independent)
- Node.js version: >= 24
- commit-echo version: latest
Additional context
Source: GitHub code scanning alerts #7, #8, #9, #10, #11. Severity: low.
Summary
Code scanning (rule
typescript:S4036) flags 5 open alerts where git is invoked by bare name ('git'), relying onPATHresolution instead of using an absolute/verified executable path. An attacker who controlsPATHcould substitute a maliciousgitbinary.Alerts:
src/git/hook.ts:47—resolveGitPath()callsexecFileSync('git', ['rev-parse', '--git-path', ...])src/git/hook.ts:219—runPostCommitHook()default callsexecSync('git log -1 --pretty=%B', ...)src/commands/batch.ts:69—gitHasChanges()callsexecSync('git diff --cached --quiet', ...)src/commands/batch.ts:81—gitHasChanges()callsexecSync('git diff --quiet', ...)src/commands/batch.ts:116—gitCommit()callsspawnSync('git', ['commit', '-F', tmpFile], ...)Expected behavior
All git invocations use a resolved, verified git executable path.
Actual behavior
The affected files call git by name, letting
PATHdecide which binary runs.Suggested fix
src/git/diff.tsalready resolves the git executable (getGitExecutable()+resolveGitExecutable()); that logic fixed the equivalent S4036 alerts indiff.ts(alerts #12–#19). Reuse it:getGitExecutable()fromsrc/git/diff.ts(or move it to a shared module) and call the resolved path inhook.tsandbatch.ts.src/commands/batch.tsoperates on arbitrary repocwds — passcwdand pass the resolved executable toexecSync/spawnSync.resolveGitPath()inhook.ts, switch fromexecSync('git ...')to the resolved executable.Environment
Additional context
Source: GitHub code scanning alerts #7, #8, #9, #10, #11. Severity: low.