Skip to content

Commit adaf20b

Browse files
satazorisaacs
authored andcommittedAug 12, 2019
Fix arguments with parenthesis causing an error on Windows
Because %* is expanded before anything, any arguments with parenthesis will make the .cmd fail with the following message: \"" was unexpected at this time This might actually be a security vulnerability because with the rightly crafted arguments, one would possibly execute arbirtrary commands, even if the arguments were properly escaped. Read https://gist.github.com/satazor/4e21543e5cd380032c2b6b38c3700223 for a more detailed explanation. To solve this, %* was moved out of the condition. PR-URL: #26 Credit: @satazor Close: #26 Reviewed-by: @isaacs
1 parent 2d277f8 commit adaf20b

File tree

2 files changed

+85
-67
lines changed

2 files changed

+85
-67
lines changed
 

‎index.js

+18-12
Original file line numberDiff line numberDiff line change
@@ -96,28 +96,34 @@ function writeShim_ (from, to, prog, args, variables, cb) {
9696
shTarget = "\"$basedir/" + shTarget + "\""
9797
}
9898

99+
// @SETLOCAL
100+
//
99101
// @IF EXIST "%~dp0\node.exe" (
100-
// "%~dp0\node.exe" "%~dp0\.\node_modules\npm\bin\npm-cli.js" %*
102+
// @SET "_prog=%~dp0\node.exe"
101103
// ) ELSE (
102-
// SETLOCAL
103-
// SET PATHEXT=%PATHEXT:;.JS;=;%
104-
// node "%~dp0\.\node_modules\npm\bin\npm-cli.js" %*
104+
// @SET "_prog=node"
105+
// @SET PATHEXT=%PATHEXT:;.JS;=;%
105106
// )
107+
//
108+
// "%_prog%" "%~dp0\.\node_modules\npm\bin\npm-cli.js" %*
109+
// @ENDLOCAL
106110
var cmd
107111
if (longProg) {
108112
shLongProg = shLongProg.trim();
109113
args = args.trim();
110-
var variableDeclarationsAsBatch = toBatchSyntax.convertToSetCommands(variables) || "";
111-
cmd = ((variableDeclarationsAsBatch.length > 0) ? ("@SETLOCAL\r\n"
112-
+ variableDeclarationsAsBatch) : "")
114+
var variableDeclarationsAsBatch = toBatchSyntax.convertToSetCommands(variables)
115+
cmd = "@SETLOCAL\r\n"
116+
+ variableDeclarationsAsBatch
117+
+ "\r\n"
113118
+ "@IF EXIST " + longProg + " (\r\n"
114-
+ " " + longProg + " " + args + " " + target + " %*\r\n"
119+
+ " @SET \"_prog=" + longProg.replace(/(^")|("$)/g, '') + "\"\r\n"
115120
+ ") ELSE (\r\n"
116-
+ " @SETLOCAL\r\n"
121+
+ " @SET \"_prog=" + prog.replace(/(^")|("$)/g, '') + "\"\r\n"
117122
+ " @SET PATHEXT=%PATHEXT:;.JS;=;%\r\n"
118-
+ " " + prog + " " + args + " " + target + " %*\r\n"
119-
+ ")"
120-
+ ((variableDeclarationsAsBatch.length > 0) ? "\r\n@ENDLOCAL" : "")
123+
+ ")\r\n"
124+
+ "\r\n"
125+
+ "\"%_prog%\" " + args + " " + target + " %*\r\n"
126+
+ '@ENDLOCAL\r\n'
121127
} else {
122128
cmd = "@" + prog + " " + args + " " + target + " %*\r\n"
123129
}

‎test/basic.js

+67-55
Original file line numberDiff line numberDiff line change
@@ -33,34 +33,37 @@ test('env shebang', function (t) {
3333
cmdShim(from, to, function(er) {
3434
if (er)
3535
throw er
36-
console.error('%j', fs.readFileSync(to, 'utf8'))
37-
console.error('%j', fs.readFileSync(to + '.cmd', 'utf8'))
3836

3937
t.equal(fs.readFileSync(to, 'utf8'),
40-
"#!/bin/sh"+
41-
"\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")"+
42-
"\n"+
43-
"\ncase `uname` in"+
44-
"\n *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;"+
45-
"\nesac"+
46-
"\n"+
47-
"\nif [ -x \"$basedir/node\" ]; then"+
48-
"\n \"$basedir/node\" \"$basedir/from.env\" \"$@\""+
49-
"\n ret=$?"+
50-
"\nelse "+
51-
"\n node \"$basedir/from.env\" \"$@\""+
52-
"\n ret=$?"+
53-
"\nfi"+
54-
"\nexit $ret"+
38+
"#!/bin/sh" +
39+
"\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")" +
40+
"\n" +
41+
"\ncase `uname` in" +
42+
"\n *CYGWIN*) basedir=`cygpath -w \"$basedir\"`;;" +
43+
"\nesac" +
44+
"\n" +
45+
"\nif [ -x \"$basedir/node\" ]; then" +
46+
"\n \"$basedir/node\" \"$basedir/from.env\" \"$@\"" +
47+
"\n ret=$?" +
48+
"\nelse " +
49+
"\n node \"$basedir/from.env\" \"$@\"" +
50+
"\n ret=$?" +
51+
"\nfi" +
52+
"\nexit $ret" +
5553
"\n")
5654
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
57-
"@IF EXIST \"%~dp0\\node.exe\" (\r"+
58-
"\n \"%~dp0\\node.exe\" \"%~dp0\\from.env\" %*\r"+
59-
"\n) ELSE (\r"+
60-
"\n @SETLOCAL\r"+
61-
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r"+
62-
"\n node \"%~dp0\\from.env\" %*\r"+
63-
"\n)")
55+
"@SETLOCAL\r" +
56+
"\n\r" +
57+
"\n@IF EXIST \"%~dp0\\node.exe\" (\r" +
58+
"\n @SET \"_prog=%~dp0\\node.exe\"\r" +
59+
"\n) ELSE (\r" +
60+
"\n @SET \"_prog=node\"\r" +
61+
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" +
62+
"\n)\r" +
63+
"\n\r" +
64+
"\n\"%_prog%\" \"%~dp0\\from.env\" %*\r" +
65+
"\n@ENDLOCAL\r" +
66+
"\n")
6467
t.end()
6568
})
6669
})
@@ -71,8 +74,6 @@ test('env shebang with args', function (t) {
7174
cmdShim(from, to, function(er) {
7275
if (er)
7376
throw er
74-
console.error('%j', fs.readFileSync(to, 'utf8'))
75-
console.error('%j', fs.readFileSync(to + '.cmd', 'utf8'))
7677

7778
t.equal(fs.readFileSync(to, 'utf8'),
7879
"#!/bin/sh"+
@@ -92,13 +93,18 @@ test('env shebang with args', function (t) {
9293
"\nexit $ret"+
9394
"\n")
9495
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
95-
"@IF EXIST \"%~dp0\\node.exe\" (\r"+
96-
"\n \"%~dp0\\node.exe\" --expose_gc \"%~dp0\\from.env.args\" %*\r"+
97-
"\n) ELSE (\r"+
98-
"\n @SETLOCAL\r"+
99-
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r"+
100-
"\n node --expose_gc \"%~dp0\\from.env.args\" %*\r"+
101-
"\n)")
96+
"@SETLOCAL\r" +
97+
"\n\r" +
98+
"\n@IF EXIST \"%~dp0\\node.exe\" (\r" +
99+
"\n @SET \"_prog=%~dp0\\node.exe\"\r" +
100+
"\n) ELSE (\r" +
101+
"\n @SET \"_prog=node\"\r" +
102+
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" +
103+
"\n)\r" +
104+
"\n\r" +
105+
"\n\"%_prog%\" --expose_gc \"%~dp0\\from.env.args\" %*\r" +
106+
"\n@ENDLOCAL\r" +
107+
"\n")
102108
t.end()
103109
})
104110
})
@@ -109,8 +115,6 @@ test('env shebang with variables', function (t) {
109115
cmdShim(from, to, function(er) {
110116
if (er)
111117
throw er
112-
console.error('%j', fs.readFileSync(to, 'utf8'))
113-
console.error('%j', fs.readFileSync(to + '.cmd', 'utf8'))
114118

115119
t.equal(fs.readFileSync(to, 'utf8'),
116120
"#!/bin/sh"+
@@ -132,14 +136,16 @@ test('env shebang with variables', function (t) {
132136
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
133137
"@SETLOCAL\r"+
134138
"\n@SET NODE_PATH=./lib:%NODE_PATH%\r"+
139+
"\n\r" +
135140
"\n@IF EXIST \"%~dp0\\node.exe\" (\r"+
136-
"\n \"%~dp0\\node.exe\" \"%~dp0\\from.env.variables\" %*\r"+
141+
"\n @SET \"_prog=%~dp0\\node.exe\"\r" +
137142
"\n) ELSE (\r"+
138-
"\n @SETLOCAL\r" +
143+
"\n @SET \"_prog=node\"\r"+
139144
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" +
140-
"\n node \"%~dp0\\from.env.variables\" %*\r"+
141145
"\n)\r"+
142-
"\n@ENDLOCAL")
146+
"\n\r"+
147+
"\n\"%_prog%\" \"%~dp0\\from.env.variables\" %*\r"+
148+
"\n@ENDLOCAL\r\n")
143149
t.end()
144150
})
145151
})
@@ -150,8 +156,6 @@ test('explicit shebang', function (t) {
150156
cmdShim(from, to, function(er) {
151157
if (er)
152158
throw er
153-
console.error('%j', fs.readFileSync(to, 'utf8'))
154-
console.error('%j', fs.readFileSync(to + '.cmd', 'utf8'))
155159

156160
t.equal(fs.readFileSync(to, 'utf8'),
157161
"#!/bin/sh" +
@@ -172,13 +176,18 @@ test('explicit shebang', function (t) {
172176
"\n")
173177

174178
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
175-
"@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" +
176-
"\n \"%~dp0\\/usr/bin/sh.exe\" \"%~dp0\\from.sh\" %*\r" +
179+
"@SETLOCAL\r" +
180+
"\n\r" +
181+
"\n@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" +
182+
"\n @SET \"_prog=%~dp0\\/usr/bin/sh.exe\"\r" +
177183
"\n) ELSE (\r" +
178-
"\n @SETLOCAL\r"+
179-
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r"+
180-
"\n /usr/bin/sh \"%~dp0\\from.sh\" %*\r" +
181-
"\n)")
184+
"\n @SET \"_prog=/usr/bin/sh\"\r" +
185+
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" +
186+
"\n)\r" +
187+
"\n\r" +
188+
"\n\"%_prog%\" \"%~dp0\\from.sh\" %*\r" +
189+
"\n@ENDLOCAL\r" +
190+
"\n")
182191
t.end()
183192
})
184193
})
@@ -189,8 +198,6 @@ test('explicit shebang with args', function (t) {
189198
cmdShim(from, to, function(er) {
190199
if (er)
191200
throw er
192-
console.error('%j', fs.readFileSync(to, 'utf8'))
193-
console.error('%j', fs.readFileSync(to + '.cmd', 'utf8'))
194201

195202
t.equal(fs.readFileSync(to, 'utf8'),
196203
"#!/bin/sh" +
@@ -211,13 +218,18 @@ test('explicit shebang with args', function (t) {
211218
"\n")
212219

213220
t.equal(fs.readFileSync(to + '.cmd', 'utf8'),
214-
"@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" +
215-
"\n \"%~dp0\\/usr/bin/sh.exe\" -x \"%~dp0\\from.sh.args\" %*\r" +
221+
"@SETLOCAL\r" +
222+
"\n\r" +
223+
"\n@IF EXIST \"%~dp0\\/usr/bin/sh.exe\" (\r" +
224+
"\n @SET \"_prog=%~dp0\\/usr/bin/sh.exe\"\r" +
216225
"\n) ELSE (\r" +
217-
"\n @SETLOCAL\r"+
218-
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r"+
219-
"\n /usr/bin/sh -x \"%~dp0\\from.sh.args\" %*\r" +
220-
"\n)")
226+
"\n @SET \"_prog=/usr/bin/sh\"\r" +
227+
"\n @SET PATHEXT=%PATHEXT:;.JS;=;%\r" +
228+
"\n)\r" +
229+
"\n\r" +
230+
"\n\"%_prog%\" -x \"%~dp0\\from.sh.args\" %*\r" +
231+
"\n@ENDLOCAL\r" +
232+
"\n")
221233
t.end()
222234
})
223235
})

0 commit comments

Comments
 (0)
Please sign in to comment.