Skip to content

Commit 3945651

Browse files
authored
Check if either the request or response ip is an internal ip. Fail the request if this is the case (#238)
1 parent 3b2a5f7 commit 3945651

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

frontend/src/lib/optics.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,49 @@ export const DEFAULT_OPTICS = [
7070
},
7171
] satisfies DefaultOpticOption[];
7272

73+
const isPrivateIp4 = (url: string) => {
74+
const parts = url.split('://');
75+
const ip =
76+
parts.length > 0
77+
? parts[parts.length - 1].replace(/\/$/, '').split(':')[0]
78+
: url.replace(/\/$/, '').split(':')[0];
79+
80+
if (/^(10)\.(.*)\.(.*)\.(.*)$/.test(ip)) return true;
81+
if (/^(172)\.(1[6-9]|2[0-9]|3[0-1])\.(.*)\.(.*)$/.test(ip)) return true;
82+
if (/^(192)\.168\.(.*)\.(.*)$/.test(ip)) return true;
83+
if (/^(127)\.(0)\.(0)\.(1)$/.test(ip)) return true;
84+
if (/^(100)\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\.(.*)\.(.*)$/.test(ip)) return true;
85+
86+
return false;
87+
};
88+
89+
const isPrivateIp6 = (url: string) => {
90+
const parts = url.split('://');
91+
const ip =
92+
parts.length > 0
93+
? parts[parts.length - 1].replace(/\/$/, '').split(':')[0]
94+
: url.replace(/\/$/, '');
95+
96+
if (/^fe80::/i.test(ip)) return true;
97+
if (/^fd[0-9a-f]{2}:/i.test(ip)) return true;
98+
99+
return false;
100+
};
101+
102+
const isPrivateIp = (url: string) => isPrivateIp4(url) || isPrivateIp6(url);
103+
73104
/**
74105
* Fetces the given `opticUrl` if allowed. The rules for which are allowed
75106
* should consider potentially malicious URLs such as `file://` or
76107
* internal/local IP addresses.
77108
*/
78109
export const fetchRemoteOptic = async (opts: { opticUrl: string; fetch?: typeof fetch }) => {
79110
if (opts.opticUrl.startsWith('file://')) return void 0;
111+
if (isPrivateIp(opts.opticUrl)) return void 0;
112+
80113
const response = await (opts.fetch ?? fetch)(opts.opticUrl);
114+
115+
if (isPrivateIp(response.url)) return void 0;
116+
81117
return await response.text();
82118
};

0 commit comments

Comments
 (0)