@@ -25,6 +25,27 @@ function buildFullUrl(baseURL: string | undefined, url: string, queryString: str
2525 return `${ base } ${ url } ?${ queryString } ` ;
2626}
2727
28+ /**
29+ * Safely checks if a URL points to the preview endpoint by parsing the hostname
30+ * This prevents substring matching vulnerabilities (e.g., evil.com/rest-preview.contentstack.com)
31+ */
32+ function isPreviewEndpoint ( url : string ) : boolean {
33+ try {
34+ // Ensure URL has a protocol for proper parsing
35+ let urlToParse = url ;
36+ if ( ! url . startsWith ( 'http://' ) && ! url . startsWith ( 'https://' ) ) {
37+ urlToParse = `https://${ url } ` ;
38+ }
39+
40+ const parsedUrl = new URL ( urlToParse ) ;
41+ // Check hostname exactly, not as substring
42+ return parsedUrl . hostname === 'rest-preview.contentstack.com' ;
43+ } catch {
44+ // If URL parsing fails, default to false for safety
45+ return false ;
46+ }
47+ }
48+
2849/**
2950 * Makes the HTTP request with proper URL handling
3051 */
@@ -36,8 +57,8 @@ async function makeRequest(
3657) : Promise < any > {
3758 // Determine URL length threshold based on whether it's a preview endpoint
3859 // rest-preview.contentstack.com has stricter limits, so use lower threshold
39- const isPreviewEndpoint = actualFullUrl . includes ( 'rest-preview.contentstack.com' ) ;
40- const urlLengthThreshold = isPreviewEndpoint ? 1500 : 2000 ;
60+ const isPreview = isPreviewEndpoint ( actualFullUrl ) ;
61+ const urlLengthThreshold = isPreview ? 1500 : 2000 ;
4162
4263 // If URL is too long, use direct axios request with full URL
4364 if ( actualFullUrl . length > urlLengthThreshold ) {
0 commit comments