VYPR
Moderate severityNVD Advisory· Published Jul 25, 2022· Updated Sep 16, 2024

Directory Traversal

CVE-2020-7649

Description

This affects the package snyk-broker before 4.73.0. It allows arbitrary file reads for users with access to Snyk's internal network via directory traversal.

AI Insight

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

Snyk Broker before 4.73.0 allows directory traversal, enabling arbitrary file reads by attackers with internal network access.

Vulnerability

Analysis

CVE-2020-7649 is a directory traversal vulnerability affecting the snyk-broker package, versions prior to 4.73.0. Snyk Broker is a component that proxies access between Snyk.io and various Git repositories (e.g., GitHub Enterprise, Bitbucket Server) and can also enable secure connections to on-premise Jira deployments [3]. The root cause is the absence of path normalization checks on incoming request URLs, allowing an attacker to use ../ sequences to escape the intended directory [4]. The fix, introduced in commit 90e0bac07a800b7c4c6646097c9c89d6b878b429, adds a check using path.normalize() to reject any URL that differs from its normalized form, effectively blocking directory traversal attempts [4].

Exploitation

To exploit this vulnerability, an attacker must have access to Snyk's internal network [2]. The attack does not require authentication beyond network access, as the Broker processes requests without validating path traversal patterns. By crafting a URL with encoded or raw ../ sequences, the attacker can force the Broker to read files outside the intended scope, such as configuration files, source code, or system files [3]. The vulnerability is classified as a CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) and has a CVSS score of 5.7 (Medium) [2].

Impact

Successful exploitation allows an attacker to arbitrarily read files accessible to the Snyk Broker process. This could lead to disclosure of sensitive information, including credentials, private keys, or internal application logic, potentially enabling further compromise of connected systems. The impact is limited to information disclosure; remote code execution is not demonstrated in the available references [1][3].

Mitigation

The vulnerability is patched in Snyk Broker version 4.73.0 and later [1][3]. Users should upgrade to this version or later immediately. The fix was released on 28 May 2020, and the vulnerability has been publicly disclosed since that date [2]. No workarounds are documented; upgrading is the recommended mitigation.

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
snyk-brokernpm
< 4.73.04.73.0

Affected products

2

Patches

1
90e0bac07a80

feat: reject paths with directory traversal

https://github.com/snyk/brokerTom RobinsonMar 18, 2020via ghsa
3 files changed · +32 8
  • lib/filters/index.js+13 7 modified
    @@ -1,6 +1,7 @@
     const minimatch = require('minimatch');
     const pathRegexp = require('path-to-regexp');
     const qs = require('qs');
    +const path = require('path');
     const undefsafe = require('undefsafe');
     const replace = require('../replace-vars');
     const authHeader = require('../auth-header');
    @@ -32,7 +33,7 @@ module.exports = ruleSource => {
       // array of entries with
       const tests = rules.map(entry => {
         const keys = [];
    -    let { method, origin, path, valid, stream } = entry;
    +    let { method, origin, path: entryPath, valid, stream } = entry;
         method = (method || 'get').toLowerCase();
         valid = valid || [];
     
    @@ -44,27 +45,32 @@ module.exports = ruleSource => {
         const fromConfig = {};
     
         // slightly bespoke version of replace-vars.js
    -    path = (path || '').replace(/(\${.*?})/g, (_, match) => {
    +    entryPath = (entryPath || '').replace(/(\${.*?})/g, (_, match) => {
           const key = match.slice(2, -1); // ditch the wrappers
           fromConfig[key] = config[key] || '';
           return ':' + key;
         });
     
         origin = replace(origin, config);
     
    -    if (path[0] !== '/') {
    -      path = '/' + path;
    +    if (entryPath[0] !== '/') {
    +      entryPath = '/' + entryPath;
         }
     
    -    logger.info({ method, path }, 'adding new filter rule');
    -    const regexp = pathRegexp(path, keys);
    +    logger.info({ method, path: entryPath }, 'adding new filter rule');
    +    const regexp = pathRegexp(entryPath, keys);
     
         return (req) => {
           // check the request method
           if (req.method.toLowerCase() !== method && method !== 'any') {
             return false;
           }
     
    +      // Do not allow directory traversal
    +      if (path.normalize(req.url) !== req.url) {
    +        return false;
    +      }
    +
           // Discard any fragments before further processing
           const mainURI = req.url.split('#')[0];
     
    @@ -133,7 +139,7 @@ module.exports = ruleSource => {
             }
           }
     
    -      logger.debug({ path, origin, url, querystring }, 'rule matched');
    +      logger.debug({ path: entryPath, origin, url, querystring }, 'rule matched');
     
           querystring = (querystring) ? `?${querystring}` : '';
           return {
    
  • test/fixtures/accept/github.json+6 0 modified
    @@ -8,6 +8,12 @@
           "method": "GET",
           "path": "/repos/:name/:repo/contents/:path*/package.json",
           "origin": "https://${GITHUB_TOKEN}@${GITHUB_API}"
    +    },
    +    {
    +      "//": "used to whitelist a folder",
    +      "method": "GET",
    +      "path": "/repos/:name/:repo/contents/:path*/docs/*",
    +      "origin": "https://${GITHUB_TOKEN}@${GITHUB_API}"
         } 
       ]
     }
    
  • test/unit/filters.test.js+13 1 modified
    @@ -7,7 +7,7 @@ const jsonBuffer = (body) => Buffer.from(JSON.stringify(body));
     
     test('Filter on URL', t => {
       t.test('for GitHub private filters', (t) => {
    -    t.plan(3);
    +    t.plan(4);
         
         const ruleSource = require(__dirname + '/../fixtures/accept/github.json');
         const filter = Filters(ruleSource.private);
    @@ -39,6 +39,18 @@ test('Filter on URL', t => {
           t.end();
         });
     
    +    t.test('should block when path includes directory traversal', (t) => {
    +      filter({
    +        url: '/repos/angular/angular/contents/path/to/docs/../../sensitive/file.js',
    +        method: 'GET',
    +      }, (error, res) => {
    +        t.equal(error.message, 'blocked', 'has been blocked');
    +        t.equal(res, undefined, 'no follow allowed');
    +      });
    +
    +      t.end();
    +    });
    +
         t.end();
       });
     
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.