Skip to content

Commit

Permalink
Bugfix: Fix command injection vulnerability in grunt tzdata pipeline
Browse files Browse the repository at this point in the history
The grunt data pipeline was constructed using full bash strings with
input coming from command line, which can lead to arbitrary code
execution.

Switch from exec to execFile, which lists all command arguments in an
array, so no injection is possible.

Advisory: GHSA-56x4-j7p9-fcf9
  • Loading branch information
ichernev committed Aug 23, 2022
1 parent 9430b4c commit ce955a3
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 18 deletions.
23 changes: 12 additions & 11 deletions tasks/data-download.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
"use strict";

var path = require('path'),
exec = require('child_process').exec;
execFile = require('child_process').execFile;

module.exports = function (grunt) {
grunt.registerTask('data-download', '1. Download data from iana.org/time-zones.', function (version) {
version = version || 'latest';

var done = this.async(),
src = 'ftp://ftp.iana.org/tz/tzdata-latest.tar.gz',
src = (version === 'latest' ?
'ftp://ftp.iana.org/tz/tzdata-latest.tar.gz' :
'https://data.iana.org/time-zones/releases/tzdata' + version + '.tar.gz'),
curl = path.resolve('temp/curl', version, 'data.tar.gz'),
dest = path.resolve('temp/download', version);

if (version !== 'latest') {
src = 'https://data.iana.org/time-zones/releases/tzdata' + version + '.tar.gz';
}

grunt.file.mkdir(path.dirname(curl));
grunt.file.mkdir(dest);

grunt.log.ok('Downloading ' + src);

exec('curl ' + src + ' -o ' + curl + ' && cd ' + dest + ' && gzip -dc ' + curl + ' | tar -xf -', function (err) {
execFile('curl', [src, '-o', curl], function (err) {
if (err) { throw err; }
grunt.log.ok('Downloaded ' + curl + ', extracting . . .');
execFile('tar', ['-xzf', curl], { cwd: dest }, function (err) {
if (err) { throw err; }

grunt.log.ok('Downloaded ' + src);

done();
grunt.log.ok('Extracted ' + dest);
done();
});
});
});
};
};
8 changes: 3 additions & 5 deletions tasks/data-zdump.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
"use strict";

var path = require('path'),
exec = require('child_process').exec;
execFile = require('child_process').execFile;

module.exports = function (grunt) {
grunt.registerTask('data-zdump', '3. Dump data with zdump(8).', function (version) {
version = version || 'latest';

console.log(path.resolve('zdump'));

var done = this.async(),
zicBase = path.resolve('temp/zic', version),
zdumpBase = path.resolve('temp/zdump', version),
Expand All @@ -34,15 +32,15 @@ module.exports = function (grunt) {
src = path.join(zicBase, file),
dest = path.join(zdumpBase, file);

exec('zdump -v ' + src, { maxBuffer: 20*1024*1024 }, function (err, stdout) {
execFile('zdump', ['-v', src], { maxBuffer: 20*1024*1024 }, function (err, stdout) {
if (err) { throw err; }

grunt.file.mkdir(path.dirname(dest));

if (stdout.length === 0) {
// on some systems, when there are no transitions then we have
// to get creative to learn the offset and abbreviation
exec('zdump UTC ' + src, { maxBuffer: 20*1024*1024 }, function (_err, _stdout) {
execFile('zdump', ['UTC', src], { maxBuffer: 20*1024*1024 }, function (_err, _stdout) {
if (_err) { throw _err; }

grunt.file.write(dest + '.zdump', normalizePaths(_stdout));
Expand Down
7 changes: 5 additions & 2 deletions tasks/data-zic.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";

var path = require('path'),
exec = require('child_process').exec;
execFile = require('child_process').execFile;

module.exports = function (grunt) {
grunt.registerTask('data-zic', '2. Compile data sources with zic(8).', function (version) {
Expand All @@ -22,7 +22,10 @@ module.exports = function (grunt) {
var file = files.shift(),
src = path.resolve('temp/download', version, file);

exec('zic -d ' + dest + ' ' + src, function (err) {
if (!grunt.file.exists(src)) {
throw new Error("Can't process " + src + " with zic. File doesn't exist");
}
execFile('zic', ['-d', dest, src], function (err) {
if (err) { throw err; }

grunt.verbose.ok('Compiled zic ' + version + ':' + file);
Expand Down

0 comments on commit ce955a3

Please sign in to comment.