Skip to content

Commit 07a661a

Browse files
fix(sec): disregard protocol-relative URL to remediate SSRF (#6539)
* fix(sec): disregard protocol-relative URL to remediate SSRF Signed-off-by: hainenber <[email protected]> * feat(test/unit/regression): add regression test to ensure SNYK-JS-AXIOS-7361793 fixed in future version Signed-off-by: hainenber <[email protected]> * chore: add EoF newline + comments Signed-off-by: hainenber <[email protected]> * chore: fix eslint issues Signed-off-by: hainenber <[email protected]> * Update SNYK-JS-AXIOS-7361793.js Co-authored-by: tom-reinders <[email protected]> --------- Signed-off-by: hainenber <[email protected]> Co-authored-by: tom-reinders <[email protected]>
1 parent c6cce43 commit 07a661a

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

lib/helpers/isAbsoluteURL.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
* @returns {boolean} True if the specified URL is absolute, otherwise false
99
*/
1010
export default function isAbsoluteURL(url) {
11-
// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
11+
// A URL is considered absolute if it begins with "<scheme>://".
1212
// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
1313
// by any combination of letters, digits, plus, period, or hyphen.
14-
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
14+
return /^([a-z][a-z\d+\-.]*:)\/\//i.test(url);
1515
}

test/specs/helpers/isAbsoluteURL.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ describe('helpers::isAbsoluteURL', function () {
1212
expect(isAbsoluteURL('!valid://example.com/')).toBe(false);
1313
});
1414

15-
it('should return true if URL is protocol-relative', function () {
16-
expect(isAbsoluteURL('//example.com/')).toBe(true);
15+
it('should return false if URL is protocol-relative', function () {
16+
expect(isAbsoluteURL('//example.com/')).toBe(false);
1717
});
1818

1919
it('should return false if URL is relative', function () {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// https://security.snyk.io/vuln/SNYK-JS-AXIOS-7361793
2+
// https://github.com/axios/axios/issues/6463
3+
4+
import axios from '../../../index.js';
5+
import http from 'http';
6+
import assert from 'assert';
7+
8+
const GOOD_PORT = 4666;
9+
const BAD_PORT = 4667;
10+
11+
describe('Server-Side Request Forgery (SSRF)', () => {
12+
let goodServer, badServer;
13+
14+
beforeEach(() => {
15+
goodServer = http.createServer(function (req, res) {
16+
res.write('good');
17+
res.end();
18+
}).listen(GOOD_PORT);
19+
badServer = http.createServer(function (req, res) {
20+
res.write('bad');
21+
res.end();
22+
}).listen(BAD_PORT);
23+
})
24+
25+
afterEach(() => {
26+
goodServer.close();
27+
badServer.close();
28+
});
29+
30+
it('should not fetch bad server', async () => {
31+
const ssrfAxios = axios.create({
32+
baseURL: 'http://localhost:' + String(GOOD_PORT),
33+
});
34+
35+
// Good payload would be `userId = '12345'`
36+
// Malicious payload is as below.
37+
const userId = '/localhost:' + String(BAD_PORT);
38+
39+
const response = await ssrfAxios.get(`/${userId}`);
40+
assert.strictEqual(response.data, 'good');
41+
assert.strictEqual(response.config.baseURL, 'http://localhost:' + String(GOOD_PORT));
42+
assert.strictEqual(response.config.url, '//localhost:' + String(BAD_PORT));
43+
assert.strictEqual(response.request.res.responseUrl, 'http://localhost:' + String(GOOD_PORT) + '/localhost:' + String(BAD_PORT));
44+
});
45+
});

0 commit comments

Comments
 (0)