Skip to content

Commit

Permalink
Use an EventEmitter to replay failed proxy connect HTTP requests (#77)
Browse files Browse the repository at this point in the history
* Use an `EventEmitter` to replay failed proxy connect HTTP requests

This is a fix for https://hackerone.com/reports/541502.

Aborts the upstream proxy connection and instead uses a vanilla
`EventEmitter` instance to replay the "data" events on to. This way,
the node core `http` Client doesn't attempt to write the HTTP request
that is intended to go to the destination server to the proxy server.

Closes #76.

* Adjust comment
  • Loading branch information
TooTallNate committed Oct 7, 2019
1 parent 5252bb9 commit 36d8cf5
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions index.js
Expand Up @@ -5,6 +5,7 @@
var net = require('net');
var tls = require('tls');
var url = require('url');
var events = require('events');
var Agent = require('agent-base');
var inherits = require('util').inherits;
var debug = require('debug')('https-proxy-agent');
Expand Down Expand Up @@ -154,20 +155,32 @@ HttpsProxyAgent.prototype.callback = function connect(req, opts, fn) {
fn(null, sock);
} else {
// some other status code that's not 200... need to re-play the HTTP header
// "data" events onto the socket once the HTTP machinery is attached so that
// the user can parse and handle the error status code
// "data" events onto the socket once the HTTP machinery is attached so
// that the node core `http` can parse and handle the error status code
cleanup();

// the original socket is closed, and a "fake socket" EventEmitter is
// returned instead, so that the proxy doesn't get the HTTP request
// written to it (which may contain `Authorization` headers or other
// sensitive data).
//
// See: https://hackerone.com/reports/541502
socket.destroy();
socket = new events.EventEmitter();

// save a reference to the concat'd Buffer for the `onsocket` callback
buffers = buffered;

// need to wait for the "socket" event to re-play the "data" events
req.once('socket', onsocket);

fn(null, socket);
}
}

function onsocket(socket) {
debug('replaying proxy buffer for failed request');

// replay the "buffers" Buffer onto the `socket`, since at this point
// the HTTP module machinery has been hooked up for the user
if (socket.listenerCount('data') > 0) {
Expand All @@ -177,7 +190,6 @@ HttpsProxyAgent.prototype.callback = function connect(req, opts, fn) {
throw new Error('should not happen...');
}

socket.resume();
// nullify the cached Buffer instance
buffers = null;
}
Expand Down

2 comments on commit 36d8cf5

@jaimeborjas
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security fixes

@donurukiran
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done with few security issues

Please sign in to comment.