From 54a0191a45d1134afb5af2d145a231536ca60f5c Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Tue, 7 Apr 2026 14:52:00 +0530 Subject: [PATCH 1/2] Customize: Don't let hardcoded regex override customize_allowed_urls filter. See #65030. --- src/js/_enqueues/wp/customize/controls.js | 13 +++++++------ src/js/_enqueues/wp/customize/preview.js | 11 +++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/js/_enqueues/wp/customize/controls.js b/src/js/_enqueues/wp/customize/controls.js index 921983e6bf78d..1eb0aee20d2d0 100644 --- a/src/js/_enqueues/wp/customize/controls.js +++ b/src/js/_enqueues/wp/customize/controls.js @@ -6574,15 +6574,10 @@ */ previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) { - var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = []; + var result = null, urlParser, queryParams, parsedAllowedUrl, matchedAllowedPath, parsedCandidateUrls = []; urlParser = document.createElement( 'a' ); urlParser.href = to; - // Abort if URL is for admin or (static) files in wp-includes or wp-content. - if ( /\/wp-(admin|includes|content)(\/|$)/.test( urlParser.pathname ) ) { - return null; - } - // Remove state query params. if ( urlParser.search.length > 1 ) { queryParams = api.utils.parseQueryString( urlParser.search.substr( 1 ) ); @@ -6613,12 +6608,18 @@ return ! _.isUndefined( _.find( previewer.allowedUrls, function( allowedUrl ) { parsedAllowedUrl.href = allowedUrl; if ( urlParser.protocol === parsedAllowedUrl.protocol && urlParser.host === parsedAllowedUrl.host && 0 === urlParser.pathname.indexOf( parsedAllowedUrl.pathname.replace( /\/$/, '' ) ) ) { + matchedAllowedPath = parsedAllowedUrl.pathname.replace( /\/$/, '' ); result = parsedCandidateUrl.href; return true; } } ) ); } ); + // Disallow links to admin, includes, and content, unless the matching allowed URL itself contains such a path. + if ( result && /\/wp-(admin|includes|content)(\/|$)/.test( urlParser.pathname.substring( matchedAllowedPath ? matchedAllowedPath.length : 0 ) ) ) { + return null; + } + return result; }); diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index 375cd2104ba0f..1cfc2c5d92a54 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -281,7 +281,7 @@ * @return {boolean} Is appropriate for changeset link. */ api.isLinkPreviewable = function isLinkPreviewable( element, options ) { - var matchesAllowedUrl, parsedAllowedUrl, args, elementHost; + var matchesAllowedUrl, matchedAllowedPath, parsedAllowedUrl, args, elementHost; args = _.extend( {}, { allowAdminAjax: false }, options || {} ); @@ -298,7 +298,10 @@ parsedAllowedUrl = document.createElement( 'a' ); matchesAllowedUrl = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) { parsedAllowedUrl.href = allowedUrl; - return parsedAllowedUrl.protocol === element.protocol && parsedAllowedUrl.host.replace( /:(80|443)$/, '' ) === elementHost && 0 === element.pathname.indexOf( parsedAllowedUrl.pathname.replace( /\/$/, '' ) ); + if ( parsedAllowedUrl.protocol === element.protocol && parsedAllowedUrl.host.replace( /:(80|443)$/, '' ) === elementHost && 0 === element.pathname.indexOf( parsedAllowedUrl.pathname.replace( /\/$/, '' ) ) ) { + matchedAllowedPath = parsedAllowedUrl.pathname.replace( /\/$/, '' ); + return true; + } } ) ); if ( ! matchesAllowedUrl ) { return false; @@ -314,8 +317,8 @@ return args.allowAdminAjax; } - // Disallow links to admin, includes, and content. - if ( /\/wp-(admin|includes|content)(\/|$)/.test( element.pathname ) ) { + // Disallow links to admin, includes, and content, unless the matching allowed URL itself contains such a path. + if ( /\/wp-(admin|includes|content)(\/|$)/.test( element.pathname.substring( matchedAllowedPath ? matchedAllowedPath.length : 0 ) ) ) { return false; } From 9c6eb3a6826c7ab3254d9cd628850a351b8f502f Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Tue, 7 Apr 2026 15:22:50 +0530 Subject: [PATCH 2/2] Customize: Initialize matchedAllowedPath to empty string to avoid ternary guard. See #65030. --- src/js/_enqueues/wp/customize/controls.js | 4 ++-- src/js/_enqueues/wp/customize/preview.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/_enqueues/wp/customize/controls.js b/src/js/_enqueues/wp/customize/controls.js index 1eb0aee20d2d0..573b2ad6d82f0 100644 --- a/src/js/_enqueues/wp/customize/controls.js +++ b/src/js/_enqueues/wp/customize/controls.js @@ -6574,7 +6574,7 @@ */ previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) { - var result = null, urlParser, queryParams, parsedAllowedUrl, matchedAllowedPath, parsedCandidateUrls = []; + var result = null, urlParser, queryParams, parsedAllowedUrl, matchedAllowedPath = '', parsedCandidateUrls = []; urlParser = document.createElement( 'a' ); urlParser.href = to; @@ -6616,7 +6616,7 @@ } ); // Disallow links to admin, includes, and content, unless the matching allowed URL itself contains such a path. - if ( result && /\/wp-(admin|includes|content)(\/|$)/.test( urlParser.pathname.substring( matchedAllowedPath ? matchedAllowedPath.length : 0 ) ) ) { + if ( result && /\/wp-(admin|includes|content)(\/|$)/.test( urlParser.pathname.substring( matchedAllowedPath.length ) ) ) { return null; } diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index 1cfc2c5d92a54..4d45633c3041b 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -281,7 +281,7 @@ * @return {boolean} Is appropriate for changeset link. */ api.isLinkPreviewable = function isLinkPreviewable( element, options ) { - var matchesAllowedUrl, matchedAllowedPath, parsedAllowedUrl, args, elementHost; + var matchesAllowedUrl, matchedAllowedPath = '', parsedAllowedUrl, args, elementHost; args = _.extend( {}, { allowAdminAjax: false }, options || {} ); @@ -318,7 +318,7 @@ } // Disallow links to admin, includes, and content, unless the matching allowed URL itself contains such a path. - if ( /\/wp-(admin|includes|content)(\/|$)/.test( element.pathname.substring( matchedAllowedPath ? matchedAllowedPath.length : 0 ) ) ) { + if ( /\/wp-(admin|includes|content)(\/|$)/.test( element.pathname.substring( matchedAllowedPath.length ) ) ) { return false; }