@@ -100,3 +100,63 @@ export default function getUserAgent (sdk, application, integration, feature) {
100100
101101 return `${ headerParts . filter ( ( item ) => item !== '' ) . join ( '; ' ) } ;`
102102}
103+
104+ // URL validation functions to prevent SSRF attacks
105+ const isValidURL = ( url ) => {
106+ try {
107+ // Allow relative URLs (they are safe as they use the same origin)
108+ if ( url . startsWith ( '/' ) || url . startsWith ( './' ) || url . startsWith ( '../' ) ) {
109+ return true
110+ }
111+
112+ // Only validate absolute URLs for SSRF protection
113+ const parsedURL = new URL ( url )
114+ return isAllowedHost ( parsedURL . hostname )
115+ } catch ( error ) {
116+ // 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 ( '\\' )
119+ }
120+ }
121+
122+ const isAllowedHost = ( hostname ) => {
123+ // Define allowed domains for Contentstack API
124+ const allowedDomains = [
125+ 'api.contentstack.io' ,
126+ 'eu-api.contentstack.com' ,
127+ 'azure-na-api.contentstack.com' ,
128+ 'azure-eu-api.contentstack.com' ,
129+ 'gcp-na-api.contentstack.com' ,
130+ 'gcp-eu-api.contentstack.com'
131+ ]
132+
133+ // Check for localhost/development environments
134+ const localhostPatterns = [
135+ 'localhost' ,
136+ '127.0.0.1' ,
137+ '0.0.0.0'
138+ ]
139+
140+ // Allow localhost for development
141+ if ( localhostPatterns . includes ( hostname ) ) {
142+ return true
143+ }
144+
145+ // Check if hostname is in allowed domains or is a subdomain of allowed domains
146+ return allowedDomains . some ( domain => {
147+ return hostname === domain || hostname . endsWith ( '.' + domain )
148+ } )
149+ }
150+
151+ export const validateAndSanitizeConfig = ( config ) => {
152+ if ( ! config || ! config . url ) {
153+ throw new Error ( 'Invalid request configuration: missing URL' )
154+ }
155+
156+ // Validate the URL to prevent SSRF attacks
157+ if ( ! isValidURL ( config . url ) ) {
158+ throw new Error ( `SSRF Prevention: URL "${ config . url } " is not allowed` )
159+ }
160+
161+ return config
162+ }
0 commit comments