Headline
CVE-2022-4022: Diff [2672900:2776612] for svg-support/trunk – WordPress Plugin Repository
The SVG Support plugin for WordPress defaults to insecure settings in version 2.5 and 2.5.1. SVG files containing malicious javascript are not sanitized. While version 2.5 adds the ability to sanitize image as they are uploaded, the plugin defaults to disable sanitization and does not restrict SVG upload to only administrators. This allows authenticated attackers, with author-level privileges and higher, to upload malicious SVG files that can be embedded in posts and pages by higher privileged users. Additionally, the embedded JavaScript is also triggered on visiting the image URL, which allows an attacker to execute malicious code in browsers visiting that URL.
svg-support/trunk/admin/admin-init.php
r2672900
r2776612
52
52
53
53
function bodhi\_sanitize\_fields( $value ) {
54
55
global $bodhi\_svgs\_options;
56
$bodhi\_plugin\_version\_stored = get\_option( 'bodhi\_svgs\_plugin\_version' );
54
57
55
58
$value\['css\_target'\] = esc\_attr( sanitize\_text\_field( $value\['css\_target'\] ) );
56
59
60
if( $value\['sanitize\_svg\_front\_end'\] !== 'on' ) {
61
62
$value\['sanitize\_svg\_front\_end'\] = false;
63
64
}
65
57
66
return $value;
58
67
svg-support/trunk/admin/svgs-settings-page.php
r2672900
r2776612
91
91
</tr>
92
92
93
<tr valign="top">
94
<!-- Allow sanitization of svg -->
95
<th scope="row">
96
<strong><?php \_e( 'Sanitize SVG while uploading', 'svg-support' ); ?></strong>
97
</th>
98
<td>
99
<label for="bodhi\_svgs\_settings\[sanitize\_svg\]">
100
<?php printf(
101
'<input id="bodhi\_svgs\_settings\[sanitize\_svg\]" name="bodhi\_svgs\_settings\[sanitize\_svg\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_sanitize\_svg', checked( isset( $bodhi\_svgs\_options\['sanitize\_svg'\] ), true, false ) ); ?>
102
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Enhance security of SVG uploads by sanitizing all svg images before being uploaded. This is helpful when non-admins are allowed to upload SVG images.<br><em>All external references are automatically removed during sanitization to prevent XSS and Injection attacks.</em>', 'svg-support' ); ?></small>
103
</label>
104
</td>
105
</tr>
106
107
<tr valign="top">
108
<!-- Allow minification of svg -->
109
<th scope="row">
110
<label for="bodhi\_svgs\_settings\[minify\_svg\]"><strong><?php \_e( 'Minify SVG', 'svg-support' ); ?></strong>
111
</th>
112
<td>
113
<label for="bodhi\_svgs\_settings\[minify\_svg\]">
114
<?php printf(
115
'<input id="bodhi\_svgs\_settings\[minify\_svg\]" name="bodhi\_svgs\_settings\[minify\_svg\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_minify\_svg', checked( isset( $bodhi\_svgs\_options\['minify\_svg'\] ), true, false ) ); ?>
116
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Enabling this option will auto-minify all svg uploads. Sanitization must be turned on for minification to work.', 'svg-support' ); ?></small>
117
</label>
118
</td>
119
</tr>
120
121
<tr valign="top">
122
<!-- Delete all plugin's data upon deletion -->
123
<th scope="row">
124
<label for="bodhi\_svgs\_settings\[del\_plugin\_data\]"><strong><?php \_e( 'Delete Plugin\\'s Data', 'svg-support' ); ?></strong>
125
</th>
126
<td>
127
<label for="bodhi\_svgs\_settings\[del\_plugin\_data\]">
128
<?php printf(
129
'<input id="bodhi\_svgs\_settings\[del\_plugin\_data\]" name="bodhi\_svgs\_settings\[del\_plugin\_data\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_del\_plugin\_data', checked( isset( $bodhi\_svgs\_options\['del\_plugin\_data'\] ), true, false ) ); ?>
130
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Delete all plugin\\'s data during uninstallation process.', 'svg-support' ); ?></small>
131
</label>
132
</td>
133
</tr>
134
93
135
<tr valign="top" class="svgs-simple">
94
136
<!-- Simple/Advanced mode selector -->
…
…
115
157
</tr>
116
158
117
<tr valign="top" class="svgs-advanced">
118
<!-- Allow sanitization of svg -->
119
<th scope="row">
120
<strong><?php \_e( 'Sanitize SVG', 'svg-support' ); ?></strong>
121
</th>
122
<td>
123
<label for="bodhi\_svgs\_settings\[sanitize\_svg\]">
124
<?php printf(
125
'<input id="bodhi\_svgs\_settings\[sanitize\_svg\]" name="bodhi\_svgs\_settings\[sanitize\_svg\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_sanitize\_svg', checked( isset( $bodhi\_svgs\_options\['sanitize\_svg'\] ), true, false ) ); ?>
126
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Enhance security of SVG uploads by saniziting all svg images before being uploaded. This is helpful when non-admins are allowed to upload SVG images.<br><em>All external references are automatically removed during sanitization to prevent XSS and Injection attacks.</em>', 'svg-support' ); ?></small>
127
</label>
128
</td>
129
</tr>
130
131
<tr valign="top" class="svgs-advanced">
132
<!-- Allow minification of svg -->
133
<th scope="row">
134
<label for="bodhi\_svgs\_settings\[minify\_svg\]"><strong><?php \_e( 'Minify SVG', 'svg-support' ); ?></strong>
135
</th>
136
<td>
137
<label for="bodhi\_svgs\_settings\[minify\_svg\]">
138
<?php printf(
139
'<input id="bodhi\_svgs\_settings\[minify\_svg\]" name="bodhi\_svgs\_settings\[minify\_svg\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_minify\_svg', checked( isset( $bodhi\_svgs\_options\['minify\_svg'\] ), true, false ) ); ?>
140
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Enabling this option will auto-minify all svg uploads.', 'svg-support' ); ?></small>
159
<tr valign="top" class="svgs-advanced">
160
<!-- Allow sanitization of svg on Front-end -->
161
162
<th scope="row">
163
<strong><?php \_e( 'Sanitize SVG on Front-end', 'svg-support' ); ?></strong>
164
</th>
165
<td>
166
<label for="bodhi\_svgs\_settings\[sanitize\_svg\_front\_end\]">
167
<?php printf(
168
'<input id="bodhi\_svgs\_settings\[sanitize\_svg\_front\_end\]" name="bodhi\_svgs\_settings\[sanitize\_svg\_front\_end\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_sanitize\_svg\_front\_end', checked( $bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\], 'on', false ) ); ?>
169
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e('Enhance security by sanitizing svg images on Front-end. This will help to prevent XSS and Injection attacks.', 'svg-support' ); ?></small>
141
170
</label>
142
171
</td>
…
…
153
182
'<input id="bodhi\_svgs\_settings\[js\_foot\_choice\]" name="bodhi\_svgs\_settings\[js\_foot\_choice\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_js\_foot\_choice', checked( isset( $bodhi\_svgs\_options\['js\_foot\_choice'\] ), true, false ) ); ?>
154
183
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e(' Normally, scripts are placed in <code>head</code> of the HTML document. If "Yes" is selected, the script is placed before the closing <code>body</code> tag. This requires the theme to have the <code>wp\_footer()</code> template tag in the appropriate place.', 'svg-support' ); ?></small>
184
</label>
185
</td>
186
</tr>
187
188
<tr valign="top" class="svgs-advanced">
189
<!-- Select whether to use vanilla Js or jQuery -->
190
<th scope="row">
191
<strong><?php \_e( 'Use Vanilla JS?', 'svg-support' ); ?></strong>
192
</th>
193
<td>
194
<label for="bodhi\_svgs\_settings\[use\_vanilla\_js\]">
195
<?php printf(
196
'<input id="bodhi\_svgs\_settings\[use\_vanilla\_js\]" name="bodhi\_svgs\_settings\[use\_vanilla\_js\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_use\_vanilla\_js', checked( isset( $bodhi\_svgs\_options\['use\_vanilla\_js'\] ), true, false ) ); ?>
197
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e(' Checking this will use vanilla JS file instead of the jQuery.', 'svg-support' ); ?></small>
155
198
</label>
156
199
</td>
…
…
185
228
186
229
<tr valign="top" class="svgs-advanced">
187
<!-- Automatically insert class to target in images when inserting into posts/pages from admin edit screen -->
188
<th scope="row">
189
<strong><?php \_e( 'Automatically insert class?', 'svg-support' ); ?></strong></label>
190
</th>
191
<td>
192
<label for="bodhi\_svgs\_settings\[auto\_insert\_class\]">
193
<?php printf(
194
'<input id="bodhi\_svgs\_settings\[auto\_insert\_class\]" name="bodhi\_svgs\_settings\[auto\_insert\_class\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_auto\_insert\_class', checked( isset( $bodhi\_svgs\_options\['auto\_insert\_class'\] ), true, false ) ); ?>
195
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e(' Checking this will make sure that either the default class or the custom one you set below is inserted into the style attributes of <code>img</code> tags when you insert SVG images into a post. Additionally, it will remove all of the default WordPress classes. It will leave normal image types as default and only affect SVG files.', 'svg-support' ); ?></small>
196
</label>
197
</td>
198
</tr>
199
200
<tr valign="top" class="svgs-advanced">
201
230
<!-- Automatically insert class to target in images on front end page via jQuery -->
202
231
<th scope="row">
…
…
208
237
'<input id="bodhi\_svgs\_settings\[force\_inline\_svg\]" name="bodhi\_svgs\_settings\[force\_inline\_svg\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_force\_inline\_svg', checked( isset( $bodhi\_svgs\_options\['force\_inline\_svg'\] ), true, false ) ); ?>
209
238
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e(' <strong>Use with caution!</strong> Checking this will automatically add the SVG class to ALL image tags containing SVG file sources in the rendered HTML via javascript and will therefore render all of your SVG files inline.<br /><em>Use case scenario: When using a visual builder such as in the Divi Theme or The Divi Builder, the class is not automatically added with the "Automatically insert class?" option selected or the builder module doesn\\'t give you the option to manually add a CSS class directly to your image.</em>', 'svg-support' ); ?></small>
239
</label>
240
</td>
241
</tr>
242
243
<tr valign="top" class="svgs-advanced">
244
<!-- Classic Editor Options Header -->
245
<th scope="row">
246
<h3 class="inner-title"><?php \_e( 'Settings for Classic Editor', 'svg-support' ); ?></h3>
247
</th>
248
<td>
249
<hr>
250
</td>
251
</tr>
252
253
<tr valign="top" class="svgs-advanced">
254
<!-- Automatically insert class to target in images when inserting into posts/pages from admin edit screen -->
255
<th scope="row">
256
<strong><?php \_e( 'Automatically insert class?', 'svg-support' ); ?></strong></label>
257
</th>
258
<td>
259
<label for="bodhi\_svgs\_settings\[auto\_insert\_class\]">
260
<?php printf(
261
'<input id="bodhi\_svgs\_settings\[auto\_insert\_class\]" name="bodhi\_svgs\_settings\[auto\_insert\_class\]" type="checkbox" %2$s />', 'bodhi\_svgs\_settings\_auto\_insert\_class', checked( isset( $bodhi\_svgs\_options\['auto\_insert\_class'\] ), true, false ) ); ?>
262
<?php \_e( 'Yes', 'svg-support' ); ?><br /><small class="description"><?php \_e(' Checking this will make sure that either the default class or the custom one you set in <b>"CSS Class to target"</b> option will be inserted into the style attributes of <code>img</code> tags when you insert SVG images into a post. Additionally, it will remove all of the default WordPress classes. It will leave normal image types as default and only affect SVG files.', 'svg-support' ); ?></small>
210
263
</label>
211
264
</td>
…
…
348
401
</div> <!-- .postbox -->
349
402
350
<!-- <a href="https://www.cloudways.com/en/woocommerce-hosting.php?id=731275&a\_bid=7c9dd1c5" target="\_top"><img style="width:100%;" src="//www.cloudways.com/affiliate/accounts/default1/banners/7c9dd1c5.jpg" alt="Load WooCommerce Stores in 249ms!" title="Load WooCommerce Stores in 249ms!" width="" height="" /></a><img style="border:0" src="https://www.cloudways.com/affiliate/scripts/imp.php?id=731275&a\_bid=7c9dd1c5" width="1" height="1" alt="" /> -->
351
<a href="https://www.cloudways.com/en/wordpress-cloud-hosting.php?id=731275&a\_bid=19515e01" target="\_top"><img style="width:100%;" src="//www.cloudways.com/affiliate/accounts/default1/banners/19515e01.jpg" alt="Load WordPress Sites in as fast as 37ms!" title="Load WordPress Sites in as fast as 37ms!" width="" height="" /></a><img style="border:0" src="https://www.cloudways.com/affiliate/scripts/imp.php?id=731275&a\_bid=19515e01" width="1" height="1" alt="" />
352
<!-- <a href="https://www.cloudways.com/en/wordpress-cloud-hosting.php?id=731275&a\_bid=08e2b8f4" target="\_top"><img style="width:100%;" src="//www.cloudways.com/affiliate/accounts/default1/banners/08e2b8f4.jpg" alt="Load WordPress Sites in as fast as 37ms!" title="Load WordPress Sites in as fast as 37ms!" width="" height="" /></a><img style="border:0" src="https://www.cloudways.com/affiliate/scripts/imp.php?id=731275&a\_bid=08e2b8f4" width="1" height="1" alt="" /> -->
353
<a href="https://www.cloudways.com/en/woocommerce-hosting.php?id=731275&a\_bid=ed78b3a7" target="\_top"><img style="width:100%;" src="//www.cloudways.com/affiliate/accounts/default1/banners/ed78b3a7.jpg" alt="Load WooCommerce Stores in 249ms!" title="Load WooCommerce Stores in 249ms!" width="" height="" /></a><img style="border:0" src="https://www.cloudways.com/affiliate/scripts/imp.php?id=731275&a\_bid=ed78b3a7" width="1" height="1" alt="" />
354
355
403
</div> <!-- .meta-box-sortables -->
356
404
svg-support/trunk/config.codekit3
r2672900
r2776612
186
186
"tS" : 0
187
187
},
188
"\\/js\\/min\\/gutenberg-filters-min.js" : {
188
"\\/js\\/svgs-inline-vanilla.js" : {
189
189
"bF" : 0,
190
190
"ft" : 64,
…
…
192
192
"mi" : 1,
193
193
"oA" : 0,
194
"oAP" : "\\/js\\/min\\/gutenberg-filters-min-min.js",
195
"oF" : 0,
196
"sC" : 3,
197
"tS" : 0
198
},
199
"\\/js\\/min\\/svgs-inline-min.js" : {
200
"bF" : 0,
201
"ft" : 64,
202
"ma" : 0,
203
"mi" : 1,
204
"oA" : 0,
205
"oAP" : "\\/js\\/min\\/svgs-inline-min-min.js",
206
"oF" : 0,
194
"oAP" : "\\/js\\/min\\/svgs-inline-vanilla-min.js",
195
"oF" : 2,
207
196
"sC" : 3,
208
197
"tS" : 0
…
…
348
337
"rq" : 75
349
338
},
339
"\\/uninstall.php" : {
340
"cB" : 0,
341
"ft" : 8192,
342
"hM" : 0,
343
"oA" : 2,
344
"oAP" : "\\/uninstall.php",
345
"oF" : 0
346
},
350
347
"\\/vendor\\/autoload.php" : {
351
348
"cB" : 0,
…
…
443
440
"oAP" : "\\/vendor\\/composer\\/platform\_check.php",
444
441
"oF" : 0
442
},
443
"\\/vendor\\/DOMPurify\\/DOMPurify.js" : {
444
"bF" : 0,
445
"ft" : 64,
446
"ma" : 0,
447
"mi" : 1,
448
"oA" : 0,
449
"oAP" : "\\/vendor\\/DOMPurify\\/DOMPurify-min.js",
450
"oF" : 0,
451
"sC" : 3,
452
"tS" : 0
453
},
454
"\\/vendor\\/DOMPurify\\/DOMPurify.min.js" : {
455
"bF" : 0,
456
"ft" : 64,
457
"ma" : 0,
458
"mi" : 1,
459
"oA" : 0,
460
"oAP" : "\\/vendor\\/DOMPurify\\/DOMPurify.min-min.js",
461
"oF" : 0,
462
"sC" : 3,
463
"tS" : 0
445
464
},
446
465
"\\/vendor\\/enshrined\\/svg-sanitize\\/.github\\/workflows\\/tests.yml" : {
svg-support/trunk/functions/attachment.php
r2672900
r2776612
299
299
if ( get\_post\_mime\_type($attachment\_id) == 'image/svg+xml' ) {
300
300
301
if ( !isset($image\[1\]) or $image\[1\] === 0 ) {
301
if ( isset($image\[1\]) && $image\[1\] === 0 ) {
302
302
$image\[1\] = 1;
303
303
}
304
if ( !isset($image\[2\]) or $image\[2\] === 0 ) {
304
if ( isset($image\[2\]) && $image\[2\] === 0 ) {
305
305
$image\[2\] = 1;
306
306
}
svg-support/trunk/functions/enqueue.php
r2672900
r2776612
71
71
}
72
72
add\_action( 'wp\_enqueue\_scripts', 'bodhi\_svgs\_frontend\_css' );
73
74
/\*\*
75
\* Enqueue front end JS
76
\*/
77
function bodhi\_svgs\_frontend\_js() {
78
79
// get the settings
80
global $bodhi\_svgs\_options;
81
82
if ( !empty( $bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\] ) && $bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\] == 'on' && bodhi\_svgs\_advanced\_mode() == true ) {
83
84
// check where the JS should be placed, header or footer
85
if ( ! empty( $bodhi\_svgs\_options\['js\_foot\_choice'\] ) ) {
86
$bodhi\_svgs\_js\_footer = true;
87
} else {
88
$bodhi\_svgs\_js\_footer = false;
89
}
90
91
// enqueue dompurify library js
92
wp\_enqueue\_script( 'bodhi-dompurify-library', BODHI\_SVGS\_PLUGIN\_URL . 'vendor/DOMPurify/DOMPurify.min.js', array(), '1.0.1', $bodhi\_svgs\_js\_footer );
93
94
}
95
96
}
97
98
add\_action( 'wp\_enqueue\_scripts', 'bodhi\_svgs\_frontend\_js', 9 );
73
99
74
100
/\*\*
…
…
150
176
}
151
177
178
// use vanilla js if user has enabled option in settings
179
if ( ! empty( $bodhi\_svgs\_options\['use\_vanilla\_js'\] ) ) {
180
181
$bodhi\_svgs\_js\_vanilla = '-vanilla';
182
183
}else{
184
185
$bodhi\_svgs\_js\_vanilla = '';
186
187
}
188
152
189
// create path for the correct js file
153
$bodhi\_svgs\_js\_path = 'js/' . $bodhi\_svgs\_js\_folder .'svgs-inline' . $bodhi\_svgs\_js\_file . '.js' ;
154
155
wp\_register\_script( 'bodhi\_svg\_inline', BODHI\_SVGS\_PLUGIN\_URL . $bodhi\_svgs\_js\_path, array( 'jquery' ), '1.0.0', $bodhi\_svgs\_js\_footer );
190
$bodhi\_svgs\_js\_path = 'js/' . $bodhi\_svgs\_js\_folder .'svgs-inline' . $bodhi\_svgs\_js\_vanilla . $bodhi\_svgs\_js\_file . '.js' ;
191
192
wp\_register\_script( 'bodhi\_svg\_inline', BODHI\_SVGS\_PLUGIN\_URL . $bodhi\_svgs\_js\_path, array( 'jquery' ), '1.0.1', $bodhi\_svgs\_js\_footer );
156
193
wp\_enqueue\_script( 'bodhi\_svg\_inline' );
157
194
…
…
159
196
'bodhi\_svg\_inline',
160
197
sprintf(
161
'cssTarget=%s;ForceInlineSVGActive=%s;',
198
'cssTarget=%s;ForceInlineSVGActive=%s;frontSanitizationEnabled=%s;',
162
199
json\_encode($css\_target\_array),
163
json\_encode($force\_inline\_svg\_active)
200
json\_encode($force\_inline\_svg\_active),
201
json\_encode($bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\])
164
202
)
165
203
);
svg-support/trunk/js/min/svgs-inline-min.js
r2672900
r2776612
1
document.addEventListener("DOMContentLoaded",(function(e){function t(e){if("IMG"===e.nodeName){var t=e.id,s=e.classList,i=e.src;if(i.endsWith("svg")){var r=new XMLHttpRequest;r.onreadystatechange=function(){if(4==r.readyState&&200==r.status){let o;data=r.responseText;const d=undefined;var i=(new DOMParser).parseFromString(data,"text/html").getElementsByTagName("svg")\[0\],a=i.id;void 0===t?void 0===a?(t="svg-replaced-"+n,i.setAttribute("id",t)):t=a:i.setAttribute("id",t),void 0!==s&&i.setAttribute("class",s+" replaced-svg svg-replaced-"+n),i.removeAttribute("xmlns:a"),e.replaceWith(i),n++}},r.open("GET",i,!1),r.send(null)}}}function s(e){if(e.childNodes.length>0)for(var n=0;n<e.childNodes.length;n++){var i;if("IMG"==e.childNodes\[n\].nodeName)t(e.childNodes\[n\]);else s(e.childNodes\[n\])}}let n=0;(bodhisvgsInlineSupport=function(){if("true"===ForceInlineSVGActive)for(var e=document.getElementsByTagName("img"),n=0;n<e.length;n++)void 0!==e\[n\].src&&e\[n\].src.match(/\\.(svg)/)&&(e\[n\].classList.contains(cssTarget.ForceInlineSVG)||e\[n\].classList.add(cssTarget.ForceInlineSVG));if(String.prototype.endsWith||(String.prototype.endsWith=function(e,t){var s=this.toString();("number"!=typeof t||!isFinite(t)||Math.floor(t)!==t||t>s.length)&&(t=s.length),t-=e.length;var n=s.lastIndexOf(e,t);return-1!==n&&n===t}),String.prototype.endsWith=function(e){var t=this.length-e.length;return t>=0&&this.lastIndexOf(e)===t},"true"===ForceInlineSVGActive)var i="img."!==cssTarget.Bodhi?cssTarget.ForceInlineSVG:"style-svg";else var i="img."!==cssTarget?cssTarget:"style-svg";i=i.replace("img.","");for(var e=document.getElementsByClassName(i),n=0;n<e.length;n++){var r;if(void 0===e\[n\].src)s(e\[n\]);else t(e\[n\])}})()}));
1
jQuery(document).ready((function($){function t(t){var e=t.attr("id"),i=t.attr("class"),s=t.attr("src");s.endsWith("svg")&&$.get(s,(function(s){var n=$(s).find("svg"),a=n.attr("id");void 0===e?void 0===a?(e="svg-replaced-"+r,n=n.attr("id",e)):e=a:n=n.attr("id",e),void 0!==i&&(n=n.attr("class",i+" replaced-svg svg-replaced-"+r)),n=n.removeAttr("xmlns:a"),"on"==frontSanitizationEnabled&&""!=n\[0\].outerHTML&&(n=DOMPurify.sanitize(n\[0\].outerHTML)),t.replaceWith(n),$(document).trigger("svg.loaded",\[e\]),r++}),"xml")}let r=0;(bodhisvgsInlineSupport=function(){if("true"===ForceInlineSVGActive&&jQuery("img").each((function(){void 0!==jQuery(this).attr("src")&&!1!==jQuery(this).attr("src")&&jQuery(this).attr("src").match(/\\.(svg)/)&&(jQuery(this).hasClass(cssTarget.ForceInlineSVG)||jQuery(this).addClass(cssTarget.ForceInlineSVG))})),String.prototype.endsWith||(String.prototype.endsWith=function(t,r){var e=this.toString();("number"!=typeof r||!isFinite(r)||Math.floor(r)!==r||r>e.length)&&(r=e.length),r-=t.length;var i=e.lastIndexOf(t,r);return-1!==i&&i===r}),String.prototype.endsWith=function(t){var r=this.length-t.length;return r>=0&&this.lastIndexOf(t)===r},"true"===ForceInlineSVGActive)var r="img."!==cssTarget.Bodhi?cssTarget.Bodhi:".style-svg";else var r="img."!==cssTarget?cssTarget:".style-svg";r=r.replace("img",""),$(r).each((function(r){void 0!==$(this).attr("src")&&!1!==$(this).attr("src")?t($(this)):$(this).find("img").each((function(r){void 0!==$(this).attr("src")&&!1!==$(this).attr("src")&&t($(this))}))}))})()}));
svg-support/trunk/js/svgs-inline.js
r2672900
r2776612
1
// wait for document to be ready
2
document.addEventListener("DOMContentLoaded", function(event) {
1
jQuery(document).ready(function ($) {
3
2
4
3
let bodhisvgsReplacements = 0;
…
…
6
5
function bodhisvgsReplace(img) {
7
6
8
// must be an image
9
if( img.nodeName !== 'IMG' ){
7
var imgID = img.attr('id');
8
var imgClass = img.attr('class');
9
var imgURL = img.attr('src');
10
11
// Set svg size to the original img size
12
// var imgWidth = $img.attr('width');
13
// var imgHeight = $img.attr('height');
14
15
if (!imgURL.endsWith('svg')) {
10
16
return;
11
17
}
12
18
13
var imgID = img.id;
14
var imgClass = img.classList;
15
var imgURL = img.src;
19
$.get(imgURL, function(data) {
16
20
17
// must be svg
18
if( !imgURL.endsWith('svg') ){
19
return;
20
}
21
// Get the SVG tag, ignore the rest
22
var $svg = $(data).find('svg');
21
23
22
var xmlHttp = new XMLHttpRequest();
23
xmlHttp.onreadystatechange = function() {
24
var svgID = $svg.attr('id');
24
25
25
if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
26
27
data = xmlHttp.responseText;
28
29
let parser = new DOMParser();
30
const doc = parser.parseFromString(data, 'text/html');
31
32
// get svg now
33
var svg = doc.getElementsByTagName('svg')\[0\];
34
35
var svgID = svg.id;
36
37
// Add replaced image's ID to the new SVG if necessary
38
if( typeof imgID === 'undefined' ){
39
if( typeof svgID === 'undefined' ) {
40
imgID = 'svg-replaced-'+bodhisvgsReplacements;
41
svg.setAttribute('id', imgID);
42
} else {
43
imgID = svgID;
44
}
26
// Add replaced image's ID to the new SVG if necessary
27
if(typeof imgID === 'undefined') {
28
if(typeof svgID === 'undefined') {
29
imgID = 'svg-replaced-'+bodhisvgsReplacements;
30
$svg = $svg.attr('id', imgID);
45
31
} else {
46
svg.setAttribute('id', imgID);
32
imgID = svgID;
47
33
}
48
49
// Add replaced image's classes to the new SVG
50
if(typeof imgClass !== 'undefined') {
51
svg.setAttribute('class', imgClass+' replaced-svg svg-replaced-'+bodhisvgsReplacements);
52
}
53
54
// Remove any invalid XML tags as per http://validator.w3.org
55
svg.removeAttribute('xmlns:a');
56
57
// Replace image with new SVG
58
img.replaceWith(svg);
59
60
bodhisvgsReplacements++;
61
34
} else {
35
$svg = $svg.attr('id', imgID);
62
36
}
63
37
64
}
65
66
xmlHttp.open("GET", imgURL, false);
67
xmlHttp.send(null);
68
69
}
70
71
function bodhisvgsIterator(node) {
72
73
if( node.childNodes.length > 0 ){
74
75
for (var i = 0; i < node.childNodes.length; i++) {
76
77
if( node.childNodes\[i\].nodeName == 'IMG' ){
78
79
// its an image... replace it too
80
var img = node.childNodes\[i\];
81
bodhisvgsReplace(img);
82
83
}else{
84
85
// go to another level
86
bodhisvgsIterator(node.childNodes\[i\]);
87
88
}
38
// Add replaced image's classes to the new SVG
39
if(typeof imgClass !== 'undefined') {
40
$svg = $svg.attr('class', imgClass+' replaced-svg svg-replaced-'+bodhisvgsReplacements);
89
41
}
90
42
91
}
43
// Remove any invalid XML tags as per http://validator.w3.org
44
$svg = $svg.removeAttr('xmlns:a');
45
46
if(frontSanitizationEnabled == 'on' && $svg\[0\]\['outerHTML'\] != "") { // Is sanitization enabled?
47
$svg = DOMPurify.sanitize($svg\[0\]\['outerHTML'\]); // Sanitize SVG code via DOMPurify library
48
}
49
50
// Add size attributes
51
// $svg = $svg.attr('width', imgWidth);
52
// $svg = $svg.attr('height', imgHeight);
53
54
// Replace image with new SVG
55
img.replaceWith($svg);
56
57
$(document).trigger('svg.loaded', \[imgID\]);
58
59
bodhisvgsReplacements++;
60
61
}, 'xml');
92
62
93
63
}
…
…
99
69
if ( ForceInlineSVGActive === 'true' ) {
100
70
101
var allImages = document.getElementsByTagName('img'); // find all images on page
71
// Find all SVG inside img and add class if it hasn't got it
72
jQuery('img').each(function() {
102
73
103
// loop on images
104
for(var i = 0; i < allImages.length ; i++) {
74
// Check if the SRC attribute is present at all
75
if ( typeof jQuery(this).attr('src') !== typeof undefined && jQuery(this).attr('src') !== false) {
105
76
106
if( typeof allImages\[i\].src !== 'undefined' ){
77
// Pick only those with the extension we want
78
if ( jQuery(this).attr('src').match(/\\.(svg)/) ) {
107
79
108
// check if it has svg
109
if( allImages\[i\].src.match(/\\.(svg)/) ){
110
111
// add our class - if not already added
112
if( !allImages\[i\].classList.contains(cssTarget.ForceInlineSVG) ){
113
114
// add class now
115
allImages\[i\].classList.add(cssTarget.ForceInlineSVG);
116
80
// Add our class name
81
if ( !jQuery(this).hasClass(cssTarget.ForceInlineSVG) ) {
82
jQuery(this).addClass(cssTarget.ForceInlineSVG);
117
83
}
118
119
84
}
120
121
85
}
122
123
124
}
125
86
});
126
87
}
127
88
…
…
149
110
// Check to see if user set alternate class
150
111
if ( ForceInlineSVGActive === 'true' ) {
151
var target = ( cssTarget.Bodhi !== 'img.' ? cssTarget.ForceInlineSVG : 'style-svg' );
112
var target = ( cssTarget.Bodhi !== 'img.' ? cssTarget.Bodhi : '.style-svg' );
152
113
} else {
153
var target = ( cssTarget !== 'img.' ? cssTarget : 'style-svg' );
114
var target = ( cssTarget !== 'img.' ? cssTarget : '.style-svg' );
154
115
}
155
116
156
// remove .img from class
157
target = target.replace("img.","");
117
target = target.replace("img","");
158
118
159
var allImages = document.getElementsByClassName(target); // find all images with force svg class
160
161
for(var i = 0; i < allImages.length ; i++) {
162
163
if( typeof allImages\[i\].src == 'undefined' ){ // not an image
164
165
bodhisvgsIterator(allImages\[i\]);
166
119
$(target).each(function(index){
120
121
// if image then send for replacement
122
if ( typeof $(this).attr('src') !== typeof undefined && $(this).attr('src') !== false) {
123
bodhisvgsReplace($(this));
167
124
}else{
168
125
169
var img = allImages\[i\];
170
bodhisvgsReplace(img);
126
// look for svg children and send for replacement
127
$(this).find("img").each(function(i){
128
129
if( typeof $(this).attr('src') !== typeof undefined && $(this).attr('src') !== false ){
130
bodhisvgsReplace($(this));
131
}
132
133
});
171
134
172
135
}
173
136
174
}
137
138
});
175
139
176
140
})(); // Execute immediately
svg-support/trunk/readme.txt
r2672900
r2776612
5
5
Requires at least: 4.8
6
6
Tested up to: 6.0
7
Requires PHP: 5.3
7
Requires PHP: 7.2
8
8
Stable tag: 2.4.2
9
9
License: GPLv2 or later
…
…
161
161
162
162
\== Changelog ==
163
164
\= 2.5 =
165
\* Cleaned up spelling mistakes and general formatting.
166
\* Addressed security concern.
167
\* Added more sanitization options - frontend and admin both supported.
168
\* Added support for SVG minification.
169
\* Added ability to choose jQuery or vanilla JS.
170
\* Added DB cleanup on uninstall.
171
\* Fixed dimensions fallback.
163
172
164
173
\= 2.4.2 =
…
…
370
379
\== Upgrade Notice ==
371
380
381
\= 2.5 =
382
Adds new features and addresses a number of recent issues raised. Please take a backup before updating!
383
372
384
\= 2.4.2 =
373
385
2.4.2 fixes srcset issue firing PHP warnings for some themes and original image IDs missing on replacement to inline SVG.
svg-support/trunk/svg-support.php
r2672900
r2776612
4
4
Plugin URI: http://wordpress.org/plugins/svg-support/
5
5
Description: Upload SVG files to the Media Library and render SVG files inline for direct styling/animation of an SVG's internal elements using CSS/JS.
6
Version: 2.4.2
6
Version: 2.5
7
7
Author: Benbodhi
8
8
Author URI: https://benbodhi.com
…
…
23
23
\* Global variables
24
24
\*/
25
$svgs\_plugin\_version = '2.4.2'; // for use on admin pages
25
$svgs\_plugin\_version = '2.5'; // for use on admin pages
26
26
$plugin\_file = plugin\_basename(\_\_FILE\_\_); // plugin file for reference
27
27
define( 'BODHI\_SVGS\_PLUGIN\_PATH', plugin\_dir\_path( \_\_FILE\_\_ ) ); // define the absolute plugin path for includes
…
…
29
29
$bodhi\_svgs\_options = get\_option('bodhi\_svgs\_settings'); // retrieve our plugin settings from the options table
30
30
31
/\*
32
\* SVG Sanitizer class
33
\*/
34
include( BODHI\_SVGS\_PLUGIN\_PATH . 'vendor/autoload.php' ); // svg sanitizer
31
use enshrined\\svgSanitize\\Sanitizer; // init svg sanitizer for usage
35
32
36
// interfaces to enable custom whitelisting of svg tags and attributes
37
include( BODHI\_SVGS\_PLUGIN\_PATH . 'includes/svg-tags.php' );
38
include( BODHI\_SVGS\_PLUGIN\_PATH . 'includes/svg-attributes.php' );
33
if ( ( !empty($bodhi\_svgs\_options\['sanitize\_svg'\]) && $bodhi\_svgs\_options\['sanitize\_svg'\] === 'on' ) || ( !empty($bodhi\_svgs\_options\['minify\_svg'\]) && $bodhi\_svgs\_options\['minify\_svg'\] === 'on' ) ) {
39
34
40
use enshrined\\svgSanitize\\Sanitizer; // init svg sanitizer for usage
41
$sanitizer = new Sanitizer(); // initialize if enabled
35
/\*
36
\* SVG Sanitizer class
37
\*/
38
include( BODHI\_SVGS\_PLUGIN\_PATH . 'vendor/autoload.php' ); // svg sanitizer
39
40
// interfaces to enable custom whitelisting of svg tags and attributes
41
include( BODHI\_SVGS\_PLUGIN\_PATH . 'includes/svg-tags.php' );
42
include( BODHI\_SVGS\_PLUGIN\_PATH . 'includes/svg-attributes.php' );
43
44
$sanitizer = new Sanitizer(); // initialize if enabled
45
46
}
42
47
43
48
/\*\*
…
…
75
80
76
81
}
82
83
// For version >= 2.5. | Enable 'sanitize\_svg\_front\_end' by default
84
if ( !isset($bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\]) ) {
85
$bodhi\_svgs\_options\['sanitize\_svg\_front\_end'\] = 'on';
86
update\_option( 'bodhi\_svgs\_settings', $bodhi\_svgs\_options );
87
}
88
svg-support/trunk/vendor/composer/platform_check.php
r2672900
r2776612
5
5
$issues = array();
6
6
7
if (!(PHP\_VERSION\_ID >= 70000)) {
8
$issues\[\] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP\_VERSION . '.';
7
if (!(PHP\_VERSION\_ID >= 50600)) {
8
$issues\[\] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP\_VERSION . '.';
9
9
}
10
10
Related news
The Chained Quiz plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'dn' parameter on the 'chainedquiz_list' page in versions up to, and including, 1.3.2.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.
The Simple:Press plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'sforum_[md5 hash of the WordPress URL]' cookie value in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This would be highly complex to exploit as it would require the attacker to set the cookie a cookie for the targeted user.
The WP Affiliate Platform plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via $_SERVER["REQUEST_URI"] in versions up to, and including, 6.3.9 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. This is unlikely to work in modern browsers.
The WP Affiliate Platform plugin for WordPress is vulnerable to Stored Cross-Site Scripting via several parameters in versions up to, and including, 6.3.9 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
The Simple:Press plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'postitem' parameter manipulated during a forum response in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping that makes injecting object and embed tags possible. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages when responding to forum threads that will execute whenever a user accesses an injected page.
The Simple:Press plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'postitem' parameter manipulated during the profile-save action when modifying a profile signature in versions up to, and including, 6.8 due to insufficient input sanitization and output escaping that makes injecting object and embed tags possible. This makes it possible for authenticated attackers, with minimal permissions, such as a subscriber to inject arbitrary web scripts in pages when modifying a profile signature that will execute whenever a user accesses an injected page.
The Appointment Hour Booking Plugin for WordPress is vulnerable to CSV Injection in versions up to, and including, 1.3.72. This makes it possible for unauthenticated attackers to embed untrusted input into content during booking creation that may be exported as a CSV file when a site's administrator exports booking details. This can result in code execution when these files are downloaded and opened on a local system with a vulnerable configuration.
The Appointment Hour Booking plugin for WordPress is vulnerable to CAPTCHA bypass in versions up to, and including, 1.3.72. This is due to the use of insufficiently strong hashing algorithm on the CAPTCHA secret that is also displayed to the user via a cookie.
The Quiz and Survey Master plugin for WordPress is vulnerable to iFrame Injection via the 'question[id]' parameter in versions up to, and including, 8.0.4 due to insufficient input sanitization and output escaping that allowed iframe tags to be injected. This makes it possible for unauthenticated attackers to inject iFrames in pages that will execute whenever a user accesses an injected page.
The Quiz and Survey Master plugin for WordPress is vulnerable to input validation bypass via the 'question[id]' parameter in versions up to, and including, 8.0.4 due to insufficient input validation that allows attackers to inject content other than the specified value (i.e. a number, file path, etc..). This makes it possible attackers to submit values other than the intended input type.
The Appointment Hour Booking plugin for WordPress is vulnerable to iFrame Injection via the ‘email’ or general field parameters in versions up to, and including, 1.3.72 due to insufficient input sanitization and output escaping that makes injecting iFrame tags possible. This makes it possible for unauthenticated attackers to inject iFrames when submitting a booking that will execute whenever a user accesses the injected booking details page.
The Theme and plugin translation for Polylang is vulnerable to authorization bypass in versions up to, and including, 3.2.16 due to missing capability checks in the process_polylang_theme_translation_wp_loaded() function. This makes it possible for unauthenticated attackers to update plugin and theme translation settings and to import translation strings.
The Betheme theme for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 26.5.1.4 via deserialization of untrusted input supplied via the import, mfn-items-import-page, and mfn-items-import parameters passed through the mfn_builder_import, mfn_builder_import_page, importdata, importsinglepage, and importfromclipboard functions. This makes it possible for authenticated attackers, with contributor level permissions and above to inject a PHP Object. The additional presence of a POP chain would make it possible for attackers to execute code, retrieve sensitive data, delete files, etc..