From ad867d45c194b80c2cad4bff59c72267485536c1 Mon Sep 17 00:00:00 2001 From: Matthijs van Henten Date: Wed, 6 Jan 2016 10:13:28 +0000 Subject: [PATCH] fixes +11379 we dont allow dangerous shell chars in scm urls ever --- node_modules/c9/scm_url_parse.js | 28 +++++++ node_modules/c9/scm_url_parse_test.js | 113 ++++++++++++++++---------- 2 files changed, 97 insertions(+), 44 deletions(-) diff --git a/node_modules/c9/scm_url_parse.js b/node_modules/c9/scm_url_parse.js index c11b503c..cc39f02c 100644 --- a/node_modules/c9/scm_url_parse.js +++ b/node_modules/c9/scm_url_parse.js @@ -10,7 +10,31 @@ define(function(require, exports, module) { }; var defaultProvider = "unknown"; + + /** + * Checks if there are unexpected (dangerous) characters in the url + * + * Source: + * + * http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html + * + * The application shall quote the following characters if they are to represent themselves: + * + * | & ; < > ( ) $ ` \ " ' + * + * and the following may need to be quoted under certain circumstances. That is, these characters may be special depending on conditions described elsewhere in this volume of IEEE Std 1003.1-2001: + * + * * ? [ # ˜ = % + */ + function containsDangerousShellCharacters(url){ + return /[\s;&|><*?`$(){}[\]!#]/.test(url); + } + module.exports = function(url) { + // scm urls cannot contain any of these + if (containsDangerousShellCharacters(url)) + return; + var m = url.match(/^(git)@([\w\.\d\-\_]+)(?:\/|:)([\w\.\d\-\_\/]+)/); if (m) { return { @@ -48,6 +72,10 @@ define(function(require, exports, module) { default: scm = parsed.pathname.match(/\.git$/) ? "git": "hg"; } + + + + return { protocol: parsed.protocol, scm: scm, diff --git a/node_modules/c9/scm_url_parse_test.js b/node_modules/c9/scm_url_parse_test.js index 44151967..726b0144 100644 --- a/node_modules/c9/scm_url_parse_test.js +++ b/node_modules/c9/scm_url_parse_test.js @@ -1,4 +1,5 @@ #!/usr/bin/env node + /*global describe it before after beforeEach afterEach */ "use strict"; @@ -11,51 +12,51 @@ require("amd-loader"); var assert = require("assert"); var parse = require("./scm_url_parse"); -describe(__filename, function(){ +describe(__filename, function() { describe("#parse", function() { it("should parse ssh url", function(done) { - var url = parse("git@github.com:fjakobs/lispjs.git"); - assert.equal(url.scm, "git"); - assert.equal(url.protocol, "ssh:"); - assert.equal(url.auth, "git"); - assert.equal(url.hostname, "github.com"); - assert.equal(url.pathname, "fjakobs/lispjs.git"); - done(); - - }), - - it("should parse git url", function(done) { - var url = parse("git://github.com/fjakobs/lispjs.git"); - assert.equal(url.scm, "git"); - assert.equal(url.protocol, "git:"); - assert.equal(url.hostname, "github.com"); - assert.equal(url.pathname, "fjakobs/lispjs.git"); - done(); - - }), - - it("should parse https url", function(done) { - var url = parse("https://fjakobs@github.com/fjakobs/lispjs.git"); - assert.equal(url.protocol, "https:"); - assert.equal(url.scm, "git"); - assert.equal(url.auth, "fjakobs"); - assert.equal(url.hostname, "github.com"); - assert.equal(url.pathname, "fjakobs/lispjs.git"); - done(); - - }), - - it("should parse Bitbucket url", function(done) { - var url = parse("git@bitbucket.org/Richard/expressling.git"); - assert.equal(url.protocol, "ssh:"); - assert.equal(url.scm, "git"); - assert.equal(url.auth, "git"); - assert.equal(url.hostname, "bitbucket.org"); - assert.equal(url.pathname, "Richard/expressling.git"); - done(); - }); - + var url = parse("git@github.com:fjakobs/lispjs.git"); + assert.equal(url.scm, "git"); + assert.equal(url.protocol, "ssh:"); + assert.equal(url.auth, "git"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + done(); + + }), + + it("should parse git url", function(done) { + var url = parse("git://github.com/fjakobs/lispjs.git"); + assert.equal(url.scm, "git"); + assert.equal(url.protocol, "git:"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + done(); + + }), + + it("should parse https url", function(done) { + var url = parse("https://fjakobs@github.com/fjakobs/lispjs.git"); + assert.equal(url.protocol, "https:"); + assert.equal(url.scm, "git"); + assert.equal(url.auth, "fjakobs"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + done(); + + }), + + it("should parse Bitbucket url", function(done) { + var url = parse("git@bitbucket.org/Richard/expressling.git"); + assert.equal(url.protocol, "ssh:"); + assert.equal(url.scm, "git"); + assert.equal(url.auth, "git"); + assert.equal(url.hostname, "bitbucket.org"); + assert.equal(url.pathname, "Richard/expressling.git"); + done(); + }); + it("should parse Bitbucket hg ssh url", function(done) { var url = parse("ssh://hg@bitbucket.org/fjakobs/juhu"); assert.equal(url.protocol, "ssh:"); @@ -64,7 +65,7 @@ describe(__filename, function(){ assert.equal(url.pathname, "fjakobs/juhu"); done(); }); - + it("should parse github URL without .git", function(done) { var url = parse("https://github.com/arunoda/meteor-streams"); assert.equal(url.protocol, "https:"); @@ -74,6 +75,30 @@ describe(__filename, function(){ assert.equal(url.pathname, "arunoda/meteor-streams"); done(); }); + + it("Should refuse a git url with dangerous shell chars in it", function() { + var validUrls = [ + "https://github.com/arunoda/meteor-streams", + "https://fjakobs@github.com/fjakobs/lispjs.git", + "ssh://hg@bitbucket.org/fjakobs/juhu", + "git@bitbucket.org/Richard/expressling.git", + "git://github.com/fjakobs/lispjs.git", + "git@github.com:fjakobs/lispjs.git", + ]; + + var exploits = [ + "&:(){ :|:& };:", + "&rm -rf /", + ";uname-a" + ]; + + validUrls.forEach(function(url) { + assert.ok(parse(url), "This url is normally valid: " + url); + + exploits.forEach(function(exploit) { + assert.equal(parse(url + exploit), undefined, "But not with an exploit: " + url + exploit); + }); + }); + }); }); - }); \ No newline at end of file