CVE-2022-1650 (JavaScript, published 2022-05-12T11:15Z)
Description: value: Improper Removal of Sensitive Information Before Storage or Transfer in GitHub repository eventsource/eventsource prior to v2.0.2.


Severity: MEDIUM (CVSS v3 base score: 9.3)
Weakness: CWE-212 \u2014 Improper Removal of Sensitive Information Before Storage or Transfer
The product stores, transfers, or shares a resource that contains sensitive information, but it does not properly remove that information before the product makes the resource available to unauthorized actors.
Repository: https://github.com/eventsource/eventsource
Files changed:
lib/eventsource.js
test/eventsource_test.js
Commit message: fix: strip sensitive headers on redirect to different origin


Vulnerable code:
    // The url may have been changed by a temporary
    // redirect. If that's the case, revert it now.
  if (eventSourceInitDict && eventSourceInitDict.headers && eventSourceInitDict.headers['Last-Event-ID']) {
    lastEventId = eventSourceInitDict.headers['Last-Event-ID']
    delete eventSourceInitDict.headers['Last-Event-ID']
    if (eventSourceInitDict && eventSourceInitDict.headers) {
      for (var i in eventSourceInitDict.headers) {
        var header = eventSourceInitDict.headers[i]
        if (!res.headers.location) {
        url = res.headers.location

Fixed code:
  var headers = eventSourceInitDict && eventSourceInitDict.headers
  var hasNewOrigin = false
    // The url may have been changed by a temporary redirect. If that's the case,
    // revert it now, and flag that we are no longer pointing to a new origin
      hasNewOrigin = false
  if (headers && headers['Last-Event-ID']) {
    lastEventId = headers['Last-Event-ID']
    delete headers['Last-Event-ID']
    if (headers) {
      var reqHeaders = hasNewOrigin ? removeUnsafeHeaders(headers) : headers
      for (var i in reqHeaders) {
        var header = reqHeaders[i]
        var location = res.headers.location
        if (!location) {
        var prevOrigin = new URL(url).origin
        var nextOrigin = new URL(location).origin
        hasNewOrigin = prevOrigin !== nextOrigin
        url = location

/**
 * Returns a new object of headers that does not include any authorization and cookie headers
 *
 * @param {Object} headers An object of headers ({[headerName]: headerValue})
 * @return {Object} a new object of headers
 * @api private
 */
function removeUnsafeHeaders (headers) {
  var safe = {}
  for (var key in headers) {
    if (/^(cookie|authorization)$/i.test(key)) {
      continue
    }

    safe[key] = headers[key]
  }

  return safe
}
    it('follows http ' + status + ' redirects, drops sensitive headers on origin change', function (done) {
      var redirectSuffix = '/foobar'
      var clientRequestedRedirectUrl = false
      var receivedHeaders = {}
      createServer(function (err, server) {
        if (err) return done(err)

        var newServerUrl = server.url.replace('http://localhost', 'http://127.0.0.1')

        server.on('request', function (req, res) {
          if (req.url === '/') {
            res.writeHead(status, {
              'Connection': 'Close',
              'Location': newServerUrl + redirectSuffix
            })
            res.end()
          } else if (req.url === redirectSuffix) {
            clientRequestedRedirectUrl = true
            receivedHeaders = req.headers
            res.writeHead(200, {'Content-Type': 'text/event-stream'})
            res.end()
          }
        })

        var es = new EventSource(server.url, {
          headers: {
            keep: 'me',
            authorization: 'Bearer someToken',
            cookie: 'some-cookie=yep'
          }
        })

        es.onopen = function () {
          assert.ok(clientRequestedRedirectUrl)
          assert.equal(newServerUrl + redirectSuffix, es.url)
          assert.equal(receivedHeaders.keep, 'me', 'safe header no longer present')
          assert.equal(typeof receivedHeaders.authorization, 'undefined', 'authorization header still present')
          assert.equal(typeof receivedHeaders.cookie, 'undefined', 'cookie header still present')
          server.close(done)
        }
      })
    })