CVE-2021-23326: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') (CWE-78)
value: This affects the package @graphql-tools/git-loader before 6.2.6. The use of exec and execSync in packages/loaders/git/src/load-git.ts allows arbitrary command injection.
CWE description: The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
CVSS v3 base score: 8.8
Published: 2021-01-20T13:15Z
Repository: https://github.com/ardatan/graphql-tools
Language: Markdown
Files changed: .changeset/green-cycles-drive.md, packages/loaders/git/src/load-git.ts
Commit date: 2021-01-13 12:22:00 +0200
Commit message: Fix vulnerability in git-loader: use execFile instead of exec (#2470)


Diff: diff --git a/.changeset/green-cycles-drive.md b/.changeset/green-cycles-drive.md
new file mode 100644
index 00000000..59d6d29c
--- /dev/null
+++ b/.changeset/green-cycles-drive.md
@@ -0,0 +1,5 @@
+---
+'@graphql-tools/git-loader': patch
+---
+
+Fix vulnerability: use execFile instead of exec
diff --git a/packages/loaders/git/src/load-git.ts b/packages/loaders/git/src/load-git.ts
index 4147d35f..0f008dff 100644
--- a/packages/loaders/git/src/load-git.ts
+++ b/packages/loaders/git/src/load-git.ts
@@ -1,21 +1,21 @@
-import { exec, execSync } from 'child_process';
+import { execFile, execFileSync } from 'child_process';
 
 type Input = { ref: string; path: string };
 
 const createLoadError = (error: any) => new Error('Unable to load file from git: ' + error);
-const createCommand = ({ ref, path }: Input) => {
-  return `git show ${ref}:${path}`;
+const createCommand = ({ ref, path }: Input): string[] => {
+  return ['show', `${ref}:${path}`];
 };
 
 /**
  * @internal
  */
 export async function loadFromGit(input: Input): Promise<string | never> {
   try {
     return await new Promise((resolve, reject) => {
-      exec(createCommand(input), { encoding: 'utf-8', maxBuffer: 1024 * 1024 * 1024 }, (error, stdout) => {
+      execFile('git', createCommand(input), { encoding: 'utf-8', maxBuffer: 1024 * 1024 * 1024 }, (error, stdout) => {
         if (error) {
           reject(error);
         } else {
           resolve(stdout);
         }
@@ -29,10 +29,10 @@ export async function loadFromGit(input: Input): Promise<string | never> {
 /**
  * @internal
  */
 export function loadFromGitSync(input: Input): string | never {
   try {
-    return execSync(createCommand(input), { encoding: 'utf-8' });
+    return execFileSync('git', createCommand(input), { encoding: 'utf-8' });
   } catch (error) {
     throw createLoadError(error);
   }
 }

Vulnerable code: import { exec, execSync } from 'child_process';
const createCommand = ({ ref, path }: Input) => {
  return `git show ${ref}:${path}`;
      exec(createCommand(input), { encoding: 'utf-8', maxBuffer: 1024 * 1024 * 1024 }, (error, stdout) => {
    return execSync(createCommand(input), { encoding: 'utf-8' });
Fixed code: ---
'@graphql-tools/git-loader': patch
---

Fix vulnerability: use execFile instead of exec
import { execFile, execFileSync } from 'child_process';
const createCommand = ({ ref, path }: Input): string[] => {
  return ['show', `${ref}:${path}`];
      execFile('git', createCommand(input), { encoding: 'utf-8', maxBuffer: 1024 * 1024 * 1024 }, (error, stdout) => {
    return execFileSync('git', createCommand(input), { encoding: 'utf-8' });