CVE-2014-9682 (published 2015-02-28T01:59Z)

The dns-sync module before 0.1.1 for node.js allows context-dependent attackers to execute arbitrary commands via shell metacharacters in the first argument to the resolve API function.

Severity: HIGH
CVSS v2 base score: 10.0 (AV:N/AC:L/Au:N/C:C/I:C/A:C)

Weakness information:
cwe_id: CWE-77
cwe_name: Improper Neutralization of Special Elements used in a Command ('Command Injection')
description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
extended_description: 
            Many protocols and products have their own custom command language. While OS or shell command strings are frequently discovered and targeted, developers may not realize that these other command languages might also be vulnerable to attacks.
         
         

Fix information:
repo_url: https://github.com/skoranga/node-dns-sync
commit_details: repo_url: https://github.com/skoranga/node-dns-sync
author: Sanjeev Koranga
author_date: 2014-11-10 15:44:07-08:00
msg: adding validation check for hostname
repository: repo_url: https://github.com/skoranga/node-dns-sync
repo_name: skoranga/node-dns-sync
description: Sync version of DNS lookup. Useful for server startup activities.
repo_language: JavaScript
owner: skoranga
file_changes: filename: dns-sync.js
change_type: ModificationType.MODIFY
diff: @@ -6,6 +6,12 @@ var net = require('net'),
     shell = require('shelljs'),
     debug = require('debug')('dns-sync');
 
+//source - http://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
+var ValidHostnameRegex = new RegExp("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$");
+
+function isValidHostName(hostname) {
+    return ValidHostnameRegex.test(hostname);
+}
 /**
  * Resolve hostname to IP address,
  * returns null in case of error
@@ -13,8 +19,14 @@ var net = require('net'),
 module.exports = {
     resolve: function resolve(hostname) {
         var output,
-            nodeBinary = process.execPath,
-            scriptPath = path.join(__dirname, "../scripts/dns-lookup-script"),
+            nodeBinary = process.execPath;
+
+        if (!isValidHostName(hostname)) {
+            console.error('Invalid hostname:', hostname);
+            return null;
+        }
+
+        var scriptPath = path.join(__dirname, "../scripts/dns-lookup-script"),
             response,
             cmd = util.format('"%s" "%s" %s', nodeBinary, scriptPath, hostname);
 

programming_language: JavaScript
filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 {
   "name": "dns-sync",
-  "version": "0.1.0",
+  "version": "0.1.1",
   "description": "dns-sync",
   "main": "index.js",
   "scripts": {
@@ -20,11 +20,11 @@
   "license": "MIT",
   "readmeFilename": "README.md",
   "dependencies": {
-    "debug" : "~0.7",
-    "shelljs": "~0.2"
+    "debug" : "^2",
+    "shelljs": "~0.3"
   },
   "devDependencies": {
-    "mocha" : "~1",
-    "jshint" : "*"
+    "mocha" : "^1",
+    "jshint" : "^2"
   }
 }

programming_language: JavaScript
filename: test.js
change_type: ModificationType.MODIFY
diff: @@ -16,4 +16,10 @@ describe('dns sync', function () {
         assert.ok(!dnsSync.resolve('www.not-google.first'));
         assert.ok(!dnsSync.resolve('www.hello-yahoo.next'));
     });
+
+    it('should fail to resolve valid dns', function () {
+        assert.ok(!dnsSync.resolve("$(id > /tmp/foo)'"));
+        assert.ok(!dnsSync.resolve("cd /tmp; rm -f /tmp/echo; env 'x=() { (a)=>\' bash -c \"echo date\"; cat /tmp/echo"));
+        assert.ok(!dnsSync.resolve("$(grep -l -z '[^)]=() {' /proc/[1-9]*/environ | cut -d/ -f3)'"));
+    });
 });

programming_language: JavaScript