Skip to content

Commit 0c7cc48

Browse files
committed
Only ignore base URL if proxy is trusted
1 parent fd8b9be commit 0c7cc48

File tree

5 files changed

+38
-15
lines changed

5 files changed

+38
-15
lines changed

library/helpers/getIPAddressFromRequest.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isIP } from "net";
22
import { isPrivateIP } from "../vulnerabilities/ssrf/isPrivateIP";
3+
import { trustProxy } from "./trustProxy";
34

45
export function getIPAddressFromRequest(req: {
56
headers: Record<string, unknown>;
@@ -57,16 +58,3 @@ function getClientIpFromXForwardedFor(value: string) {
5758

5859
return null;
5960
}
60-
61-
function trustProxy() {
62-
if (!process.env.AIKIDO_TRUST_PROXY) {
63-
// Trust proxy by default
64-
// Most of the time, the application is behind a reverse proxy
65-
return true;
66-
}
67-
68-
return (
69-
process.env.AIKIDO_TRUST_PROXY === "1" ||
70-
process.env.AIKIDO_TRUST_PROXY === "true"
71-
);
72-
}

library/helpers/trustProxy.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as t from "tap";
2+
import { trustProxy } from "./trustProxy";
3+
4+
t.beforeEach(() => {
5+
delete process.env.AIKIDO_TRUST_PROXY;
6+
});
7+
8+
t.test("the default is true", async () => {
9+
t.equal(trustProxy(), true);
10+
});
11+
12+
t.test("trust proxy set to false", async () => {
13+
process.env.AIKIDO_TRUST_PROXY = "false";
14+
t.equal(trustProxy(), false);
15+
});
16+
17+
t.test("trust proxy set to true", async () => {
18+
process.env.AIKIDO_TRUST_PROXY = "true";
19+
t.equal(trustProxy(), true);
20+
});

library/helpers/trustProxy.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { envToBool } from "./envToBool";
2+
3+
export function trustProxy() {
4+
if (!process.env.AIKIDO_TRUST_PROXY) {
5+
// Trust proxy by default
6+
// Most of the time, the application is behind a reverse proxy
7+
return true;
8+
}
9+
10+
return envToBool(process.env.AIKIDO_TRUST_PROXY);
11+
}

library/vulnerabilities/ssrf/checkContextForSSRF.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SOURCES } from "../../agent/Source";
55
import { getPathsToPayload } from "../../helpers/attackPath";
66
import { extractStringsFromUserInputCached } from "../../helpers/extractStringsFromUserInputCached";
77
import { getPortFromURL } from "../../helpers/getPortFromURL";
8+
import { trustProxy } from "../../helpers/trustProxy";
89
import { tryParseURL } from "../../helpers/tryParseURL";
910
import { containsPrivateIPAddress } from "./containsPrivateIPAddress";
1011
import { findHostnameInUserInput } from "./findHostnameInUserInput";
@@ -33,10 +34,11 @@ export function checkContextForSSRF({
3334
return;
3435
}
3536

36-
if (context.url) {
37+
if (trustProxy() && context.url) {
3738
// We don't want to block outgoing requests to the same host as the server
3839
// (often happens that we have a match on headers like `Host`, `Origin`, `Referer`, etc.)
3940
// We have to check the port as well, because the hostname can be the same but with a different port
41+
// If Node.js is exposed to the internet, we can't be sure about the Host header
4042
const baseURL = tryParseURL(context.url);
4143
if (
4244
baseURL &&

library/vulnerabilities/ssrf/findHostnameInContext.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Source, SOURCES } from "../../agent/Source";
33
import { getPathsToPayload } from "../../helpers/attackPath";
44
import { extractStringsFromUserInputCached } from "../../helpers/extractStringsFromUserInputCached";
55
import { getPortFromURL } from "../../helpers/getPortFromURL";
6+
import { trustProxy } from "../../helpers/trustProxy";
67
import { tryParseURL } from "../../helpers/tryParseURL";
78
import { findHostnameInUserInput } from "./findHostnameInUserInput";
89

@@ -19,10 +20,11 @@ export function findHostnameInContext(
1920
context: Context,
2021
port: number | undefined
2122
): HostnameLocation | undefined {
22-
if (context.url) {
23+
if (trustProxy() && context.url) {
2324
// We don't want to block outgoing requests to the same host as the server
2425
// (often happens that we have a match on headers like `Host`, `Origin`, `Referer`, etc.)
2526
// We have to check the port as well, because the hostname can be the same but with a different port
27+
// If Node.js is exposed to the internet, we can't be sure about the Host header
2628
const baseURL = tryParseURL(context.url);
2729
if (
2830
baseURL &&

0 commit comments

Comments
 (0)