javascript.lang.security.spawn-git-clone.spawn-git-clone

Community Favorite
profile photo of semgrepsemgrep
Author
50,288
Download Count*

Git allows shell commands to be specified in ext URLs for remote repositories. For example, git clone 'ext::sh -c whoami% >&2' will execute the whoami command to try to connect to a remote repository. Make sure that the URL is not controlled by external input.

Run Locally

Run in CI

Defintion

rules:
  - id: spawn-git-clone
    message: Git allows shell commands to be specified in ext URLs for remote
      repositories. For example, git clone 'ext::sh -c whoami% >&2' will execute
      the whoami command to try to connect to a remote repository. Make sure
      that the URL is not controlled by external input.
    metadata:
      cwe:
        - "CWE-78: Improper Neutralization of Special Elements used in an OS
          Command ('OS Command Injection')"
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      category: security
      technology:
        - git
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Command Injection
    languages:
      - javascript
      - typescript
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: spawn('git', ['clone',...,$F])
          - pattern: $X.spawn('git', ['clone',...,$F])
          - pattern: spawn('git', ['clone',...,$P,$F])
          - pattern: $X.spawn('git', ['clone',...,$P,$F])
      - pattern-not: spawn('git', ['clone',...,"..."])
      - pattern-not: $X.spawn('git', ['clone',...,"..."])
      - pattern-not: spawn('git', ['clone',...,"...","..."])
      - pattern-not: $X.spawn('git', ['clone',...,"...","..."])

Examples

spawn-git-clone.js

function test1() {
    const { spawn } = require('child_process');
    function downloadGitCommit1(gitBranch, gitUrl, sourceCodePath) {
        // ruleid: spawn-git-clone
        const gitClone = spawn('git', [
            'clone',
            '--branch', gitBranch,
            '--depth', '1',
            gitUrl,
            sourceCodePath
        ]);
        return gitClone;
    }
}

function test2() {
    const childProcess = require('child_process');
    function downloadGitCommit2(req, res) {
        // ruleid: spawn-git-clone
        const gitClone = childProcess.spawn('git', [
            'clone',
            '--depth', '1',
            req.body.gitUrl
        ]);
        return res.send('ok');
    }
}

function test3() {
    const childProcess = require('child_process');
    function downloadGitCommit3(gitUrl) {
        // ruleid: spawn-git-clone
        const gitClone = childProcess.spawn('git', [ 'clone', gitUrl ]);
        return res.send('ok');
    }
}

function testOk1() {
    const { spawn } = require('child_process');
    function downloadGitCommitOk1() {
        // ok: spawn-git-clone
        const gitClone = spawn('git', [ 'clone', 'https://hardcoded-url.com' ]);
        return res.send('ok');
    }
}

function testOk2() {
    const childProcess = require('child_process');
    const gitUrl = 'https://hardcoded-url.com';
    function downloadGitCommitOk2() {
        // ok: spawn-git-clone
        const gitClone = childProcess.spawn('git', [ 'clone', gitUrl ]);
        return res.send('ok');
    }
}