@@ -104,18 +104,43 @@ export default function getUserAgent (sdk, application, integration, feature) {
104
104
// URL validation functions to prevent SSRF attacks
105
105
const isValidURL = ( url ) => {
106
106
try {
107
+ // Reject obviously malicious patterns early
108
+ if ( url . includes ( '@' ) || url . includes ( 'file://' ) || url . includes ( 'ftp://' ) ) {
109
+ return false
110
+ }
111
+
107
112
// Allow relative URLs (they are safe as they use the same origin)
108
113
if ( url . startsWith ( '/' ) || url . startsWith ( './' ) || url . startsWith ( '../' ) ) {
109
114
return true
110
115
}
111
116
112
117
// Only validate absolute URLs for SSRF protection
113
118
const parsedURL = new URL ( url )
119
+
120
+ // Reject non-HTTP(S) protocols
121
+ if ( ! [ 'http:' , 'https:' ] . includes ( parsedURL . protocol ) ) {
122
+ return false
123
+ }
124
+
125
+ // Prevent IP addresses in URLs to avoid internal network access
126
+ const ipv4Regex = / ^ ( \d { 1 , 3 } \. ) { 3 } \d { 1 , 3 } $ /
127
+ const ipv6Regex = / ^ \[ ? ( [ 0 - 9 a - f A - F ] { 0 , 4 } : ) { 2 , 7 } [ 0 - 9 a - f A - F ] { 0 , 4 } \] ? $ /
128
+ if ( ipv4Regex . test ( parsedURL . hostname ) || ipv6Regex . test ( parsedURL . hostname ) ) {
129
+ // Only allow localhost IPs in development
130
+ const isDevelopment = process . env . NODE_ENV === 'development' ||
131
+ process . env . NODE_ENV === 'test' ||
132
+ ! process . env . NODE_ENV
133
+ const localhostIPs = [ '127.0.0.1' , '0.0.0.0' , '::1' , 'localhost' ]
134
+ if ( ! isDevelopment || ! localhostIPs . includes ( parsedURL . hostname ) ) {
135
+ return false
136
+ }
137
+ }
138
+
114
139
return isAllowedHost ( parsedURL . hostname )
115
140
} catch ( error ) {
116
141
// If URL parsing fails, it might be a relative URL without protocol
117
- // Allow it if it doesn't contain protocol indicators
118
- return ! url . includes ( '://' ) && ! url . includes ( '\\' )
142
+ // Allow it if it doesn't contain protocol indicators or suspicious patterns
143
+ return ! url . includes ( '://' ) && ! url . includes ( '\\' ) && ! url . includes ( '@' )
119
144
}
120
145
}
121
146
@@ -137,8 +162,12 @@ const isAllowedHost = (hostname) => {
137
162
'0.0.0.0'
138
163
]
139
164
140
- // Allow localhost for development
141
- if ( localhostPatterns . includes ( hostname ) ) {
165
+ // Only allow localhost in development environments to prevent SSRF in production
166
+ const isDevelopment = process . env . NODE_ENV === 'development' ||
167
+ process . env . NODE_ENV === 'test' ||
168
+ ! process . env . NODE_ENV // Default to allowing in non-production if NODE_ENV is not set
169
+
170
+ if ( isDevelopment && localhostPatterns . includes ( hostname ) ) {
142
171
return true
143
172
}
144
173
0 commit comments