VYPR
Moderate severityNVD Advisory· Published Jul 20, 2020· Updated Aug 4, 2024

Command injection in codecov (npm package)

CVE-2020-15123

Description

A command injection vulnerability in Codecov's npm package allowed attackers to execute arbitrary commands via backtick payloads, bypassing an earlier incomplete fix.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A command injection vulnerability in Codecov's npm package allowed attackers to execute arbitrary commands via backtick payloads, bypassing an earlier incomplete fix.

Vulnerability

Overview

The upload method in the codecov npm package (prior to version 3.7.1) contains a command injection vulnerability [1]. An earlier attempt to fix this issue (CVE-2020-7597) only blocked the & character, leaving the package still susceptible to injection using backticks, which are interpreted by the shell [1].

Attack

Vector and Prerequisites The vulnerability arises from the use of execSync to call system commands (e.g., git ls-files || hg locate) with unsanitized user-controllable input [3]. The fix replaced execSync with execFileSync, which does not spawn a shell, thus preventing command injection [3][4]. While the attack surface is considered low, exploitation is possible if a malicious actor can influence the arguments passed to the upload method [1]. However, in typical usage—where the module is used directly in a build pipeline rather than as a library accepting external input—the risk is reduced [1].

Impact

Successful exploitation allows an attacker to execute arbitrary operating system commands on the host running the Codecov tool, potentially compromising the build environment, exfiltrating secrets, or pivoting to other systems within the CI/CD pipeline [1].

Mitigation

Users should upgrade to codecov version 3.7.1 or later, which resolves the vulnerability by using execFileSync instead of execSync [3][4]. No workarounds other than updating the package have been identified.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
codecovnpm
< 3.7.13.7.1

Affected products

2

Patches

1
c0711c656686

Switch from execSync to execFileSync (#180)

https://github.com/codecov/codecov-nodeJoe BecherJul 17, 2020via ghsa
3 files changed · +46 18
  • .idea/.gitignore+7 0 added
    @@ -0,0 +1,7 @@
    +# Default ignored files
    +/shelf/
    +/workspace.xml
    +# Editor-based HTTP Client requests
    +/httpRequests/
    +
    +.idea/
    \ No newline at end of file
    
  • lib/codecov.js+37 18 modified
    @@ -4,21 +4,23 @@ var request = require('teeny-request').teenyRequest
     var urlgrey = require('urlgrey')
     var jsYaml = require('js-yaml')
     var walk = require('ignore-walk')
    +var execFileSync = require('child_process').execFileSync
     var execSync = require('child_process').execSync
     
     var detectProvider = require('./detect')
     
     var version = 'v' + require('../package.json').version
     
    -var patterns,
    -  more_patterns = ''
    +var patterns = ''
    +var more_patterns = ''
    +var winPatterns = ''
     
     var isWindows =
       process.platform.match(/win32/) || process.platform.match(/win64/)
     
     if (!isWindows) {
    -  patterns =
    -    "-type f \\( -name '*coverage.*' " +
    +  patterns = (
    +    "-type f -name '*coverage.*' " +
         "-or -name 'nosetests.xml' " +
         "-or -name 'jacoco*.xml' " +
         "-or -name 'clover.xml' " +
    @@ -29,7 +31,7 @@ if (!isWindows) {
         "-or -name '*.lcov' " +
         "-or -name 'gcov.info' " +
         "-or -name '*.gcov' " +
    -    "-or -name '*.lst' \\) " +
    +    "-or -name '*.lst' " +
         "-not -name '*.sh' " +
         "-not -name '*.data' " +
         "-not -name '*.py' " +
    @@ -76,9 +78,10 @@ if (!isWindows) {
         "-not -path '*/$bower_components/*' " +
         "-not -path '*/node_modules/*' " +
         "-not -path '*/conftest_*.c.gcov'"
    +  ).split(' ')
     } else {
    -  patterns =
    -    '/a-d /b /s *coverage.* ' +
    +  winPatterns = (
    +    '/a:-d /b /s *coverage.* ' +
         '/s nosetests.xml ' +
         '/s jacoco*.xml ' +
         '/s clover.xml ' +
    @@ -136,6 +139,7 @@ if (!isWindows) {
         '| findstr /i /v \\\\$bower_components\\ ' +
         '| findstr /i /v \\node_modules\\ ' +
         '| findstr /i /v \\conftest_.*\\.c\\.gcov '
    +  ).split(' ')
     }
     
     var sendToCodecovV2 = function(
    @@ -355,7 +359,7 @@ var upload = function(args, on_success, on_failure) {
       console.log('==> Building file structure')
       try {
         upload +=
    -      execSync('git ls-files || hg locate', { cwd: root })
    +      execFileSync('git', ['ls-files', '||', 'hg', 'locate'], { cwd: root })
             .toString()
             .trim() + '\n<<<<<< network\n'
       } catch (err) {
    @@ -414,7 +418,7 @@ var upload = function(args, on_success, on_failure) {
           }
           debug.push(gcov)
           console.log('    $ ' + gcov)
    -      execSync(gcov)
    +      execFileSync(gcov)
         } catch (e) {
           console.log('    Failed to run gcov command.')
         }
    @@ -431,19 +435,23 @@ var upload = function(args, on_success, on_failure) {
           .toString()
           .trim()
       } else {
    -    bowerrc = execSync('if exist .bowerrc type .bowerrc', { cwd: root })
    -      .toString()
    -      .trim()
    +    bowerrc = fs.existsSync('.bowerrc')
       }
       if (bowerrc) {
         bowerrc = JSON.parse(bowerrc).directory
         if (bowerrc) {
           if (!isWindows) {
    -        more_patterns =
    -          " -not -path '*/" + bowerrc.toString().replace(/\/$/, '') + "/*'"
    +        more_patterns = (
    +          " -not -path '*/" +
    +          bowerrc.toString().replace(/\/$/, '') +
    +          "/*'"
    +        ).split(' ')
           } else {
    -        more_patterns =
    -          '| findstr /i /v \\' + bowerrc.toString().replace(/\/$/, '') + '\\'
    +        more_patterns = (
    +          '| findstr /i /v \\' +
    +          bowerrc.toString().replace(/\/$/, '') +
    +          '\\'
    +        ).split(' ')
           }
         }
       }
    @@ -474,15 +482,26 @@ var upload = function(args, on_success, on_failure) {
       } else if ((args.options.disable || '').split(',').indexOf('search') === -1) {
         console.log('==> Scanning for reports')
         var _files
    +    var _findArgs
         if (!isWindows) {
    -      _files = execSync('find ' + root + ' ' + patterns + more_patterns)
    +      // @TODO support for a root directory
    +      // It's not straightforward due to the nature of the find command
    +      _findArgs = [root].concat(patterns)
    +      if (more_patterns) {
    +        _findArgs.concat(more_patterns)
    +      }
    +      _files = execFileSync('find', _findArgs)
             .toString()
             .trim()
             .split('\n')
         } else {
           // @TODO support for a root directory
           // It's not straightforward due to the nature of the dir command
    -      _files = execSync('dir ' + patterns + more_patterns)
    +      _findArgs = [root].concat(winPatterns)
    +      if (more_patterns) {
    +        _findArgs.concat(more_patterns)
    +      }
    +      _files = execSync('dir ' + winPatterns.join(' ') + more_patterns)
             .toString()
             .trim()
             .split('\r\n')
    
  • README.md+2 0 modified
    @@ -116,3 +116,5 @@ If you're seeing an **HTTP 400 error when uploading reports to S3**, make sure y
     - v3.6.3 Fix for AWS Codebuild & package updates
     - v3.6.4 Fix Cirrus CI
     - v3.7.0 Remove the X-Amz-Acl: public-read header
    +
    +.
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.