PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / compatibility / class-wpo-wp-kses-compatibility.php

class-wpo-wp-kses-compatibility.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at compatibility/class-wpo-wp-kses-compatibility.php

164 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) die('No direct access allowed');
3
4 if (!class_exists('WPO_WP_Kses_Compatibility')) :
5
6 /**
7 * Adds compatibility for WP KSES plugin.
8 */
9 class WPO_WP_Kses_Compatibility {
10
11 /**
12 * Explicit list of data-* attributes used in plugin's HTML output.
13 *
14 * @var array<string>
15 */
16 private static $allowed_attrs = array(
17 'data-alt-label',
18 'data-attachment-id',
19 'data-background',
20 'data-background-image',
21 'data-blog',
22 'data-blog_id',
23 'data-colname',
24 'data-count',
25 'data-disabled',
26 'data-embed',
27 'data-enable',
28 'data-filename',
29 'data-id',
30 'data-iframe-attr',
31 'data-label',
32 'data-max',
33 'data-menuslug',
34 'data-mode',
35 'data-no-image-dimensions',
36 'data-optimizable',
37 'data-optimization',
38 'data-optimization_id',
39 'data-optimization_run_sort_order',
40 'data-page',
41 'data-post_id',
42 'data-saveas',
43 'data-sort',
44 'data-src',
45 'data-srcset',
46 'data-tab',
47 'data-table',
48 'data-tablename',
49 'data-title',
50 'data-tooltip',
51 'data-tweak',
52 'data-type',
53 'data-url',
54 'data-video-url',
55 'data-whichpage',
56 'data-wpo-lcp',
57 );
58
59 /**
60 * Attribute names that are never permitted through this class's filter, regardless of what 'wpo_kses_allowed_attrs' returns.
61 * These grant script execution or resource injection independent of the value assigned to them.
62 *
63 * @var array<string>
64 */
65 private static $blocked_attrs = array(
66 'style',
67 'srcdoc',
68 'formaction',
69 );
70
71 /**
72 * Constructor.
73 */
74 private function __construct() {
75 add_filter('wp_kses_allowed_html', array($this, 'wp_kses_allowed_html'), 10, 2);
76 }
77
78 /**
79 * Returns singleton instance.
80 *
81 * @return WPO_WP_Kses_Compatibility
82 */
83 public static function instance() {
84 static $_instance = null;
85 if (null === $_instance) {
86 $_instance = new self();
87 }
88 return $_instance;
89 }
90
91 /**
92 * Add extra attributes to allowed HTML tags for wp_kses, for tags that are already permitted in the given context.
93 *
94 * @param array<string, array<string, bool>> $allowed_tags Allowed HTML tags and attributes.
95 * @param string $context Context for which the allowed tags are being filtered.
96 *
97 * @return array<string, array<string, bool>> Modified allowed HTML tags and attributes.
98 */
99 public function wp_kses_allowed_html($allowed_tags, $context) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $context is required by the filter but not used in this function
100 $attrs = $this->sanitize_allowed_attrs(
101 apply_filters('wpo_kses_allowed_attrs', self::$allowed_attrs)
102 );
103
104 if (!is_array($allowed_tags)) {
105 return $allowed_tags;
106 }
107
108 foreach (array_keys($allowed_tags) as $tag) {
109 foreach ($attrs as $attr) {
110 $allowed_tags[$tag][$attr] = true;
111 }
112 }
113
114 return $allowed_tags;
115 }
116
117 /**
118 * Validate a list of attribute names before they're merged into kses's allowlist.
119 *
120 * $allowed_attrs is exposed via the 'wpo_kses_allowed_attrs' filter,
121 * so third-party code can add to or replace the list before it reaches wp_kses_allowed_html().
122 * Without this check, a hook (malicious or just careless) could inject event-handler
123 * attributes or other script-bearing attribute names directly into kses's allowlist,
124 * defeating the sanitizer it's meant to support.
125 * This rejects malformed names, event handlers (on*), and a small denylist of other high-risk attribute names
126 *
127 * @param mixed $attrs Attribute list, expected to be an array of strings.
128 *
129 * @return array<string> Filtered list of attribute names safe to add to kses's allowlist.
130 */
131 private function sanitize_allowed_attrs($attrs) {
132 if (!is_array($attrs)) {
133 return self::$allowed_attrs;
134 }
135
136 /** @var array<string> $sanitized */
137 $sanitized = array();
138
139 foreach ($attrs as $attr) {
140 if (!is_string($attr)) {
141 continue;
142 }
143
144 if (!preg_match('/^[a-z][a-z0-9_-]*$/', $attr)) {
145 continue;
146 }
147
148 if (0 === stripos($attr, 'on')) {
149 continue;
150 }
151
152 if (in_array(strtolower($attr), self::$blocked_attrs, true)) {
153 continue;
154 }
155
156 $sanitized[] = $attr;
157 }
158
159 return $sanitized;
160 }
161 }
162
163 endif;
164