Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c124eb5
Update wp_custom_css_cb to rely on HTML API for safe SCRIPT tag print…
sirreal Dec 17, 2025
e055156
Wrap customizer CSS test in newlines
sirreal Dec 17, 2025
33f9616
Use HTML API for style tags in script-loader
sirreal Dec 17, 2025
606539e
Use HTML Tag Processor to produce WP_Styles style tags
sirreal Dec 17, 2025
c938d4c
Use HTML Tag Processor for STYLE tags in theme.php
sirreal Dec 17, 2025
dd919f1
Build font style tags with HTML API
sirreal Dec 23, 2025
d29900a
PICKME: Update font tests to use semantic HTML comparison
sirreal Dec 23, 2025
6c6a72b
Use HTML API for hide header text
sirreal Dec 23, 2025
aad4744
Revert "Use HTML API for hide header text"
sirreal Dec 23, 2025
c3ae9a9
Merge branch 'trunk' into styles/use-html-api-for-style-tags
sirreal Dec 26, 2025
4e88745
Fix lint
sirreal Dec 26, 2025
d296d6c
Merge branch 'trunk' into styles/use-html-api-for-style-tags
sirreal Dec 29, 2025
d8a6f02
Merge branch 'styles/use-html-api-for-style-tags' into 64418/customiz…
sirreal Dec 29, 2025
67500e0
Allow arbitrary customizer custom CSS
sirreal Dec 29, 2025
01b6fb8
Fix lints
sirreal Dec 29, 2025
0141653
Restore STYLE tag trailing newline
sirreal Dec 29, 2025
6585099
Restore STYLE tag trailing newlines in theme.php
sirreal Dec 29, 2025
b0020d8
Merge branch 'styles/use-html-api-for-style-tags' into 64418/customiz…
sirreal Dec 29, 2025
407d43f
Move trailing newline out of Tag Processor
sirreal Dec 30, 2025
ffd5b45
Merge branch 'styles/use-html-api-for-style-tags' into 64418/customiz…
sirreal Dec 30, 2025
8268865
Merge branch 'trunk' into 64418/customizer-allow-arbitrary-custom-css
sirreal Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,35 +144,6 @@ public function value() {
return $value;
}

/**
* Validate a received value for being valid CSS.
*
* Checks for imbalanced braces, brackets, and comments.
* Notifications are rendered when the customizer state is saved.
*
* @since 4.7.0
* @since 4.9.0 Checking for balanced characters has been moved client-side via linting in code editor.
* @since 5.9.0 Renamed `$css` to `$value` for PHP 8 named parameter support.
*
* @param string $value CSS to validate.
* @return true|WP_Error True if the input was validated, otherwise WP_Error.
*/
public function validate( $value ) {
// Restores the more descriptive, specific name for use within this method.
$css = $value;

$validity = new WP_Error();

if ( preg_match( '#</?\w+#', $css ) ) {
$validity->add( 'illegal_markup', __( 'Markup is not allowed in CSS.' ) );
}

if ( ! $validity->has_errors() ) {
$validity = parent::validate( $css );
}
return $validity;
}

/**
* Store the CSS setting value in the custom_css custom post type for the stylesheet.
*
Expand Down
11 changes: 11 additions & 0 deletions src/wp-includes/theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,13 @@ function wp_update_custom_css_post( $css, $args = array() ) {

// Update post if it already exists, otherwise create a new one.
$post = wp_get_custom_css_post( $args['stylesheet'] );

// Remove KSES HTML filters to prevent CSS mangling.
$priority = has_filter( 'content_save_pre', 'wp_filter_post_kses' );
if ( false !== $priority ) {
remove_filter( 'content_save_pre', 'wp_filter_post_kses', $priority );
}

if ( $post ) {
$post_data['ID'] = $post->ID;
$r = wp_update_post( wp_slash( $post_data ), true );
Expand All @@ -2163,6 +2170,10 @@ function wp_update_custom_css_post( $css, $args = array() ) {
}
}

if ( false !== $priority ) {
add_filter( 'content_save_pre', 'wp_filter_post_kses', $priority );
}

if ( is_wp_error( $r ) ) {
return $r;
}
Expand Down
46 changes: 21 additions & 25 deletions tests/phpunit/tests/customize/custom-css-setting.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,27 @@ public function test_get_custom_css_post_queries_after_failed_lookup() {
$this->assertSame( get_num_queries(), $queries_before );
}

/**
* Ensure that dangerous STYLE tag contents do not break HTML output.
*
* @ticket 64418
*/
public function test_wp_custom_css_cb_escapes_dangerous_html() {
wp_update_custom_css_post(
'*::before { content: "</style><script>alert(1)</script>"; }',
array(
'stylesheet' => $this->setting->stylesheet,
)
);
$output = get_echo( 'wp_custom_css_cb' );
$expected = <<<'HTML'
<style id="wp-custom-css" type="text/css">
*::before { content: "\3c\2fstyle><script>alert(1)</script>"; }
</style>
HTML;
$this->assertEqualHTML( $expected, $output );
}

/**
* Test that wp_update_custom_css_post() updates the 'custom_css_post_id' theme mod.
*
Expand Down Expand Up @@ -373,29 +394,4 @@ public function filter_update_custom_css_data( $data, $args ) {
$data['post_title'] = 'Ignored';
return $data;
}

/**
* Tests that validation errors are caught appropriately.
*
* Note that the $validity \WP_Error object must be reset each time
* as it picks up the Errors and passes them to the next assertion.
*
* @covers WP_Customize_Custom_CSS_Setting::validate
*/
public function test_validate() {

// Empty CSS throws no errors.
$result = $this->setting->validate( '' );
$this->assertTrue( $result );

// Basic, valid CSS throws no errors.
$basic_css = 'body { background: #f00; } h1.site-title { font-size: 36px; } a:hover { text-decoration: none; } input[type="text"] { padding: 1em; }';
$result = $this->setting->validate( $basic_css );
$this->assertTrue( $result );

// Check for markup.
$unclosed_comment = $basic_css . '</style>';
$result = $this->setting->validate( $unclosed_comment );
$this->assertArrayHasKey( 'illegal_markup', $result->errors );
}
}
Loading