Package: release.debian.org Severity: normal Tags: buster User: release.debian....@packages.debian.org Usertags: pu
Hi, [ Reason ] npm is vulnerable to CVE-2020-15095: password in URL are stored in logs. This fixes import upstream commit to fix it. [ Impact ] (What is the impact for the user if the update isn't approved?) Little CVE: URL containing password (https://user:pwd@xxx) are stored in logs [ Tests ] autopkgtest tested, no specific test for this CVE [ Risks ] (Discussion of the risks involved. E.g. code is trivial or complex, alternatives available.) Low risk: minor change in logs only [ Checklist ] [X] *all* changes are documented in the d/changelog [X] I reviewed all changes and I approve them [X] attach debdiff against the package in (old)stable [X] the issue is verified as fixed in unstable [ Changes ] (Explain *all* the changes) Log strings are parsed by a new "lib/utils/replace-info.js" to delete password in URLs before logging [ Other info ] None
diff --git a/debian/changelog b/debian/changelog index d7b986f..a567e2e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +npm (5.8.0+ds6-4+deb10u2) buster; urgency=medium + + * Team upload + * Don't show password in logs (Closes: CVE-2020-15095) + + -- Xavier Guimard <y...@debian.org> Fri, 28 Aug 2020 13:36:33 +0200 + npm (5.8.0+ds6-4+deb10u1) buster; urgency=medium * Add patches to fix arbitrary path access diff --git a/debian/patches/CVE-2020-15095.diff b/debian/patches/CVE-2020-15095.diff new file mode 100644 index 0000000..9188249 --- /dev/null +++ b/debian/patches/CVE-2020-15095.diff @@ -0,0 +1,133 @@ +Description: chore: remove auth info from logs +Author: claudiahdz <cghr1...@gmail.com> +Origin: upstream, https://github.com/npm/cli/commit/a9857b8f +Bug: https://github.com/npm/cli/security/advisories/GHSA-93f3-23rq-pjfp +Forwarded: not-needed +Reviewed-By: Xavier Guimard <y...@debian.org> +Last-Update: 2020-08-28 + +--- a/bin/npm-cli.js ++++ b/bin/npm-cli.js +@@ -35,6 +35,7 @@ + var npm = require('../lib/npm.js') + var npmconf = require('../lib/config/core.js') + var errorHandler = require('../lib/utils/error-handler.js') ++ var replaceInfo = require('../lib/utils/replace-info.js') + var output = require('../lib/utils/output.js') + + var configDefs = npmconf.defs +@@ -48,7 +49,8 @@ + process.argv.splice(1, 1, 'npm', '-g') + } + +- log.verbose('cli', process.argv) ++ var args = replaceInfo(process.argv) ++ log.verbose('cli', args) + + var conf = nopt(types, shorthands) + npm.argv = conf.argv.remain +--- a/lib/fetch-package-metadata.js ++++ b/lib/fetch-package-metadata.js +@@ -3,6 +3,7 @@ + const deprCheck = require('./utils/depr-check') + const path = require('path') + const log = require('npmlog') ++const pacote = require('pacote') + const readPackageTree = require('read-package-tree') + const rimraf = require('rimraf') + const validate = require('aproba') +@@ -10,8 +11,8 @@ + const npm = require('./npm') + const npmlog = require('npmlog') + const limit = require('call-limit') +-const tempFilename = require('./utils/temp-filename') +-const pacote = require('pacote') ++const tempFilename = require('./utils/temp-filename.js') ++const replaceInfo = require('./utils/replace-info.js') + let pacoteOpts + const isWindows = require('./utils/is-windows.js') + +@@ -19,7 +20,9 @@ + validate('SOF|SZF|OOF|OZF', [spec, tracker, done]) + return (er, pkg) => { + if (er) { +- log.silly('fetchPackageMetaData', 'error for ' + String(spec), er.message) ++ er.message = replaceInfo(er.message) ++ var spc = replaceInfo(String(spec)) ++ log.silly('fetchPackageMetaData', 'error for ' + spc, er.message) + if (tracker) tracker.finish() + } + return done(er, pkg) +--- a/lib/utils/error-handler.js ++++ b/lib/utils/error-handler.js +@@ -13,6 +13,7 @@ + var chain = require('slide').chain + var writeFileAtomic = require('write-file-atomic') + var errorMessage = require('./error-message.js') ++var replaceInfo = require('./replace-info.js') + var stopMetrics = require('./metrics.js').stop + var mkdirp = require('mkdirp') + var fs = require('graceful-fs') +@@ -176,14 +177,16 @@ + ].forEach(function (k) { + var v = er[k] + if (!v) return ++ v = replaceInfo(v) + log.verbose(k, v) + }) + + log.verbose('cwd', process.cwd()) + + var os = require('os') ++ var args = replaceInfo(process.argv) + log.verbose('', os.type() + ' ' + os.release()) +- log.verbose('argv', process.argv.map(JSON.stringify).join(' ')) ++ log.verbose('argv', args.map(JSON.stringify).join(' ')) + log.verbose('node', process.version) + log.verbose('npm ', 'v' + npm.version) + +--- a/lib/utils/error-message.js ++++ b/lib/utils/error-message.js +@@ -2,12 +2,17 @@ + var npm = require('../npm.js') + var util = require('util') + var nameValidator = require('validate-npm-package-name') ++var replaceInfo = require('./replace-info.js') + + module.exports = errorMessage + + function errorMessage (er) { + var short = [] + var detail = [] ++ ++ er.message = replaceInfo(er.message) ++ er.stack = replaceInfo(er.stack) ++ + switch (er.code) { + case 'ECONNREFUSED': + short.push(['', er]) +--- /dev/null ++++ b/lib/utils/replace-info.js +@@ -0,0 +1,22 @@ ++const URL = require('url') ++ ++// replaces auth info in an array ++// of arguments or in a strings ++function replaceInfo (arg) { ++ const isArray = Array.isArray(arg) ++ const isString = typeof arg === 'string' ++ ++ if (!isArray && !isString) return arg ++ ++ const args = isString ? arg.split(' ') : arg ++ const info = args.map(arg => { ++ try { ++ const url = new URL(arg) ++ return url.password === '' ? arg : arg.replace(url.password, '***') ++ } catch (e) { return arg } ++ }) ++ ++ return isString ? info.join(' ') : info ++} ++ ++module.exports = replaceInfo diff --git a/debian/patches/series b/debian/patches/series index 95031c5..1780486 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -13,3 +13,4 @@ CVE-2019-16775-bin-links.diff CVE-2019-16775-npm-packlist.diff CVE-2019-16775-pacote.diff CVE-2019-16775-add-npm-normalize-package-bin.diff +CVE-2020-15095.diff