Headline
CVE-2019-18854: Changeset 2185438 – WordPress Plugin Repository
A Denial Of Service vulnerability exists in the safe-svg (aka Safe SVG) plugin through 1.9.4 for WordPress, related to unlimited recursion for a ‘<use … xlink:href="#identifier">’ substring.
safe-svg/trunk
- Property svn:ignore set to
.git
composer.json
- Property svn:ignore set to
safe-svg/trunk/lib/composer.lock
r1949836
r2185438
9
9
{
10
10
"name": "enshrined/svg-sanitize",
11
"version": "0.9.2",
11
"version": "0.12.0",
12
12
"source": {
13
13
"type": "git",
14
14
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
15
"reference": "e0cb5ad3abea5459e0962cf79a92d34714c74dfa"
15
"reference": "51ca4b713f3706d6b27769c6296bbc0c28a5bbd0"
16
16
},
17
17
"dist": {
18
18
"type": "zip",
19
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/e0cb5ad3abea5459e0962cf79a92d34714c74dfa",
20
"reference": "e0cb5ad3abea5459e0962cf79a92d34714c74dfa",
19
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/51ca4b713f3706d6b27769c6296bbc0c28a5bbd0",
20
"reference": "51ca4b713f3706d6b27769c6296bbc0c28a5bbd0",
21
21
"shasum": ""
22
},
23
"require": {
24
"ext-dom": "\*",
25
"ext-libxml": "\*"
22
26
},
23
27
"require-dev": {
…
…
33
37
"notification-url": "https://packagist.org/downloads/",
34
38
"license": \[
35
"GPL-2.0+"
39
"GPL-2.0\-or-later"
36
40
\],
37
41
"authors": \[
…
…
42
46
\],
43
47
"description": "An SVG sanitizer for PHP",
44
"time": "2018-10-01T17:11:02+00:00"
48
"time": "2019-10-21T22:39:08+00:00"
45
49
}
46
50
\],
safe-svg/trunk/lib/vendor/composer/installed.json
r1949836
r2185438
2
2
{
3
3
"name": "enshrined/svg-sanitize",
4
"version": "0.9.2",
5
"version\_normalized": "0.9.2.0",
4
"version": "0.12.0",
5
"version\_normalized": "0.12.0.0",
6
6
"source": {
7
7
"type": "git",
8
8
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
9
"reference": "e0cb5ad3abea5459e0962cf79a92d34714c74dfa"
9
"reference": "51ca4b713f3706d6b27769c6296bbc0c28a5bbd0"
10
10
},
11
11
"dist": {
12
12
"type": "zip",
13
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/e0cb5ad3abea5459e0962cf79a92d34714c74dfa",
14
"reference": "e0cb5ad3abea5459e0962cf79a92d34714c74dfa",
13
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/51ca4b713f3706d6b27769c6296bbc0c28a5bbd0",
14
"reference": "51ca4b713f3706d6b27769c6296bbc0c28a5bbd0",
15
15
"shasum": ""
16
},
17
"require": {
18
"ext-dom": "\*",
19
"ext-libxml": "\*"
16
20
},
17
21
"require-dev": {
…
…
19
23
"phpunit/phpunit": "^6"
20
24
},
21
"time": "2018-10-01T17:11:02+00:00",
25
"time": "2019-10-21T22:39:08+00:00",
22
26
"type": "library",
23
27
"installation-source": "dist",
…
…
29
33
"notification-url": "https://packagist.org/downloads/",
30
34
"license": \[
31
"GPL-2.0+"
35
"GPL-2.0\-or-later"
32
36
\],
33
37
"authors": \[
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/.gitignore
r1680702
r2185438
2
2
/build
3
3
/.idea
4
composer.lock
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/README.md
r1600797
r2185438
49
49
\`$sanitizer->removeRemoteReferences(true);\`
50
50
51
\## Viewing Sanitisation Issues
52
53
You may use the \`getXmlIssues()\` method to return an array of issues that occurred during sanitisation.
54
55
This may be useful for logging or providing feedback to the user on why an SVG was refused.
56
57
\`$issues = $sanitizer->getXmlIssues();\`
58
51
59
\## Minification
52
60
…
…
64
72
\[Michael Potter\](https://github.com/heyMP) has kindly created a Drupal module for this library which is available at: \[https://www.drupal.org/project/svg\_sanitizer\](https://www.drupal.org/project/svg\_sanitizer)
65
73
74
\## TYPO3
75
76
An integration for TYPO3 CMS of this library is available as composer package \`t3g/svg-sanitizer\` at \[https://bitbucket.typo3.com/projects/EXT/repos/svg\_sanitizer/\](https://bitbucket.typo3.com/projects/EXT/repos/svg\_sanitizer/)
77
66
78
\## Tests
67
79
68
You can run these by running \`phpunit\`
80
You can run these by running \`vendor/bin/phpunit\` from the base directory of this package.
81
82
\## Standalone scanning of files via CLI
83
84
Thanks to the work by \[gudmdharalds\](https://github.com/gudmdharalds) there's now a standalone scanner that can be used via the CLI.
85
86
Any errors will be output in JSON format. See \[the PR\](https://github.com/darylldoyle/svg-sanitizer/pull/25) for an example.
87
88
Use it as follows: \`php svg-scanner.php ~/svgs/myfile.svg\`
69
89
70
90
\## To-Do
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/composer.json
r1949836
r2185438
2
2
"name": "enshrined/svg-sanitize",
3
3
"description": "An SVG sanitizer for PHP",
4
"license": "GPL-2.0+",
4
"license": "GPL-2.0\-or-later",
5
5
"authors": \[
6
6
{
…
…
14
14
}
15
15
},
16
"autoload-dev": {
17
"psr-4": {
18
"enshrined\\\\svgSanitize\\\\Tests\\\\": "tests"
19
}
20
},
16
21
"minimum-stability": "stable",
17
"require": {},
22
"require": {
23
"ext-dom": "\*",
24
"ext-libxml": "\*"
25
},
18
26
"require-dev": {
19
27
"phpunit/phpunit": "^6",
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/src/Sanitizer.php
r1949836
r2185438
3
3
namespace enshrined\\svgSanitize;
4
4
5
use DOMDocument;
6
5
use enshrined\\svgSanitize\\data\\AllowedAttributes;
7
6
use enshrined\\svgSanitize\\data\\AllowedTags;
8
7
use enshrined\\svgSanitize\\data\\AttributeInterface;
9
8
use enshrined\\svgSanitize\\data\\TagInterface;
9
use enshrined\\svgSanitize\\data\\XPath;
10
use enshrined\\svgSanitize\\ElementReference\\Resolver;
11
use enshrined\\svgSanitize\\ElementReference\\Subject;
10
12
11
13
/\*\*
…
…
20
22
\* Regex to catch script and data values in attributes
21
23
\*/
22
const SCRIPT\_REGEX = '/(?:\\w+script|data):/xi';
23
24
/\*\*
25
\* @var DOMDocument
24
const SCRIPT\_REGEX = '/(?:\\w+script|data)(?:\\s)?:/xi';
25
26
/\*\*
27
\* @var \\DOMDocument
26
28
\*/
27
29
protected $xmlDocument;
…
…
53
55
54
56
/\*\*
57
\* @var int
58
\*/
59
protected $useThreshold = 1000;
60
61
/\*\*
55
62
\* @var bool
56
63
\*/
…
…
61
68
\*/
62
69
protected $xmlOptions = LIBXML\_NOEMPTYTAG;
70
71
/\*\*
72
\* @var array
73
\*/
74
protected $xmlIssues = array();
75
76
/\*\*
77
\* @var Resolver
78
\*/
79
protected $elementReferenceResolver;
63
80
64
81
/\*\*
…
…
77
94
protected function resetInternal()
78
95
{
79
$this->xmlDocument = new DOMDocument();
96
$this->xmlDocument = new \\DOMDocument();
80
97
$this->xmlDocument->preserveWhiteSpace = false;
81
98
$this->xmlDocument->strictErrorChecking = false;
…
…
86
103
\* Set XML options to use when saving XML
87
104
\* See: DOMDocument::saveXML
88
\*
105
\*
89
106
\* @param int $xmlOptions
90
107
\*/
…
…
94
111
}
95
112
96
/\*\*
113
/\*\*
97
114
\* Get XML options to use when saving XML
98
115
\* See: DOMDocument::saveXML
99
\*
116
\*
100
117
\* @return int
101
118
\*/
102
119
public function getXMLOptions()
103
120
{
104
return $this->xmlOptions;
121
return $this->xmlOptions;
105
122
}
106
123
…
…
154
171
$this->removeRemoteReferences = $removeRemoteRefs;
155
172
}
173
174
/\*\*
175
\* Get XML issues.
176
\*
177
\* @return array
178
\*/
179
public function getXmlIssues() {
180
return $this->xmlIssues;
181
}
182
156
183
157
184
/\*\*
…
…
184
211
$this->removeDoctype();
185
212
213
// Pre-process all identified elements
214
$xPath = new XPath($this->xmlDocument);
215
$this->elementReferenceResolver = new Resolver($xPath);
216
$this->elementReferenceResolver->collect();
186
217
// Grab all the elements
187
218
$allElements = $this->xmlDocument->getElementsByTagName("\*");
…
…
218
249
// Suppress the errors because we don't really have to worry about formation before cleansing
219
250
libxml\_use\_internal\_errors(true);
251
252
// Reset array of altered XML
253
$this->xmlIssues = array();
220
254
}
221
255
…
…
253
287
// see comments at: http://php.net/manual/en/class.domnamednodemap.php
254
288
for ($i = $elements->length - 1; $i >= 0; $i--) {
289
/\*\* @var \\DOMElement $currentElement \*/
255
290
$currentElement = $elements->item($i);
256
291
…
…
258
293
if (!in\_array(strtolower($currentElement->tagName), $this->allowedTags)) {
259
294
$currentElement->parentNode->removeChild($currentElement);
295
$this->xmlIssues\[\] = array(
296
'message' => 'Suspicious tag \\'' . $currentElement->tagName . '\\'',
297
'line' => $currentElement->getLineNo(),
298
);
260
299
continue;
261
300
}
…
…
267
306
$this->cleanHrefs($currentElement);
268
307
308
if ($this->isTaggedInvalid($currentElement)) {
309
$currentElement->parentNode->removeChild($currentElement);
310
$this->xmlIssues\[\] = array(
311
'message' => 'Invalid \\'' . $currentElement->tagName . '\\'',
312
'line' => $currentElement->getLineNo(),
313
);
314
continue;
315
}
316
269
317
if (strtolower($currentElement->tagName) === 'use') {
270
if ($this->isUseTagDirty($currentElement)) {
318
if ($this->isUseTagDirty($currentElement)
319
|| $this->isUseTagExceedingThreshold($currentElement)
320
) {
271
321
$currentElement->parentNode->removeChild($currentElement);
322
$this->xmlIssues\[\] = array(
323
'message' => 'Suspicious \\'' . $currentElement->tagName . '\\'',
324
'line' => $currentElement->getLineNo(),
325
);
272
326
continue;
273
327
}
…
…
289
343
// Remove attribute if not in whitelist
290
344
if (!in\_array(strtolower($attrName), $this->allowedAttrs) && !$this->isAriaAttribute(strtolower($attrName)) && !$this->isDataAttribute(strtolower($attrName))) {
345
291
346
$element->removeAttribute($attrName);
347
$this->xmlIssues\[\] = array(
348
'message' => 'Suspicious attribute \\'' . $attrName . '\\'',
349
'line' => $element->getLineNo(),
350
);
292
351
}
293
352
…
…
297
356
if (isset($element->attributes->item($x)->value) && $this->hasRemoteReference($element->attributes->item($x)->value)) {
298
357
$element->removeAttribute($attrName);
358
$this->xmlIssues\[\] = array(
359
'message' => 'Suspicious attribute \\'' . $attrName . '\\'',
360
'line' => $element->getLineNo(),
361
);
299
362
}
300
363
}
…
…
319
382
))) {
320
383
$element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
384
$this->xmlIssues\[\] = array(
385
'message' => 'Suspicious attribute \\'href\\'',
386
'line' => $element->getLineNo(),
387
);
388
389
321
390
}
322
391
}
…
…
333
402
if (preg\_match(self::SCRIPT\_REGEX, $href) === 1) {
334
403
$element->removeAttribute('href');
404
$this->xmlIssues\[\] = array(
405
'message' => 'Suspicious attribute \\'href\\'',
406
'line' => $element->getLineNo(),
407
);
335
408
}
336
409
}
…
…
388
461
389
462
/\*\*
463
\* Whether \`<use ... xlink:href="#identifier">\` elements shall be
464
\* removed in case expansion would exceed this threshold.
465
\*
466
\* @param int $useThreshold
467
\*/
468
public function useThreshold($useThreshold = 1000)
469
{
470
$this->useThreshold = (int)$useThreshold;
471
}
472
473
/\*\*
390
474
\* Check to see if an attribute is an aria attribute or not
391
475
\*
…
…
412
496
413
497
/\*\*
498
\* Determines whether element is used in a Subject that has the "invalid" tag.
499
\*
500
\* @param \\DOMElement $element
501
\* @return bool
502
\*/
503
protected function isTaggedInvalid(\\DOMElement $element)
504
{
505
$subject = $this->elementReferenceResolver->findByElement($element, true);
506
return $subject !== null && $subject->matchesTags(\[Subject::TAG\_INVALID\]);
507
}
508
509
/\*\*
414
510
\* Make sure our use tag is only referencing internal resources
415
511
\*
…
…
419
515
protected function isUseTagDirty(\\DOMElement $element)
420
516
{
421
$xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
422
if ($xlinks && substr($xlinks, 0, 1) !== '#') {
423
return true;
424
}
425
517
$href = Helper::getElementHref($element);
518
return $href && strpos($href, '#') !== 0;
519
}
520
521
/\*\*
522
\* Determines whether \`<use ... xlink:href="#identifier">\` is expanded
523
\* recursively in order to create DoS scenarios. The amount of a actually
524
\* used element needs to be below \`$this->useThreshold\`.
525
\*
526
\* @param \\DOMElement $element
527
\* @return bool
528
\*/
529
protected function isUseTagExceedingThreshold(\\DOMElement $element)
530
{
531
if ($this->useThreshold <= 0) {
532
return false;
533
}
534
$useId = Helper::extractIdReferenceFromHref(
535
Helper::getElementHref($element)
536
);
537
if ($useId === null) {
538
return false;
539
}
540
foreach ($this->elementReferenceResolver->findByElementId($useId) as $subject) {
541
if ($subject->countUse() >= $this->useThreshold) {
542
return true;
543
}
544
}
426
545
return false;
427
546
}
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/src/data/AttributeInterface.php
r1192094
r2185438
1
1
<?php
2
3
4
2
namespace enshrined\\svgSanitize\\data;
5
3
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/src/data/TagInterface.php
r1192094
r2185438
1
1
<?php
2
3
4
2
namespace enshrined\\svgSanitize\\data;
5
6
3
7
4
/\*\*
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/tests/AllowedAttributesTest.php
r1949836
r2185438
1
1
<?php
2
namespace enshrined\\svgSanitize\\Tests;
2
3
3
use \\enshrined\\svgSanitize\\data\\AllowedAttributes;
4
use enshrined\\svgSanitize\\data\\AllowedAttributes;
4
5
use PHPUnit\\Framework\\TestCase;
5
6
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/tests/AllowedTagsTest.php
r1949836
r2185438
1
1
<?php
2
namespace enshrined\\svgSanitize\\Tests;
2
3
3
use \\enshrined\\svgSanitize\\data\\AllowedTags;
4
use enshrined\\svgSanitize\\data\\AllowedTags;
4
5
use PHPUnit\\Framework\\TestCase;
5
6
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/tests/SanitizerTest.php
r1949836
r2185438
1
1
<?php
2
require 'data/TestAllowedTags.php';
3
require 'data/TestAllowedAttributes.php';
4
5
use \\enshrined\\svgSanitize\\Sanitizer;
2
namespace enshrined\\svgSanitize\\Tests;
3
4
use enshrined\\svgSanitize\\Sanitizer;
5
use enshrined\\svgSanitize\\Tests\\Fixtures\\TestAllowedAttributes;
6
use enshrined\\svgSanitize\\Tests\\Fixtures\\TestAllowedTags;
6
7
use PHPUnit\\Framework\\TestCase;
7
8
…
…
19
20
\* Set up the test class
20
21
\*/
21
public function setUp()
22
protected function setUp()
22
23
{
23
24
$this->class = new Sanitizer();
24
25
}
25
26
27
protected function tearDown()
28
{
29
unset($this->class);
30
}
31
26
32
/\*\*
27
33
\* Make sure the initial tags are loaded
…
…
54
60
55
61
$this->assertInternalType('array', $tags);
56
$this->assertEquals(TestAllowedTags::getTags(), $tags);
62
63
$this->assertEquals(array\_map('strtolower', TestAllowedTags::getTags()), $tags);
57
64
}
58
65
…
…
67
74
68
75
$this->assertInternalType('array', $attributes);
69
$this->assertEquals(TestAllowedAttributes::getAttributes(), $attributes);
76
77
$this->assertEquals( array\_map('strtolower', TestAllowedAttributes::getAttributes()), $attributes);
70
78
}
71
79
…
…
75
83
public function testSanitizeXMLDoc()
76
84
{
77
$initialData = file\_get\_contents('tests/data/xmlTestOne.xml');
78
$expected = file\_get\_contents('tests/data/xmlCleanOne.xml');
85
$dataDirectory = \_\_DIR\_\_ . '/data';
86
$initialData = file\_get\_contents($dataDirectory . '/xmlTestOne.xml');
87
$expected = file\_get\_contents($dataDirectory . '/xmlCleanOne.xml');
79
88
80
89
$cleanData = $this->class->sanitize($initialData);
…
…
88
97
public function testSanitizeSVGDoc()
89
98
{
90
$initialData = file\_get\_contents('tests/data/svgTestOne.svg');
91
$expected = file\_get\_contents('tests/data/svgCleanOne.svg');
99
$dataDirectory = \_\_DIR\_\_ . '/data';
100
$initialData = file\_get\_contents($dataDirectory . '/svgTestOne.svg');
101
$expected = file\_get\_contents($dataDirectory . '/svgCleanOne.svg');
92
102
93
103
$cleanData = $this->class->sanitize($initialData);
…
…
101
111
public function testBadXMLReturnsFalse()
102
112
{
103
$initialData = file\_get\_contents('tests/data/badXmlTestOne.svg');
113
$dataDirectory = \_\_DIR\_\_ . '/data';
114
$initialData = file\_get\_contents($dataDirectory . '/badXmlTestOne.svg');
104
115
105
116
$cleanData = $this->class->sanitize($initialData);
…
…
113
124
public function testSanitizeHrefs()
114
125
{
115
$initialData = file\_get\_contents('tests/data/hrefTestOne.svg');
116
$expected = file\_get\_contents('tests/data/hrefCleanOne.svg');
126
$dataDirectory = \_\_DIR\_\_ . '/data';
127
$initialData = file\_get\_contents($dataDirectory . '/hrefTestOne.svg');
128
$expected = file\_get\_contents($dataDirectory . '/hrefCleanOne.svg');
117
129
118
130
$cleanData = $this->class->sanitize($initialData);
…
…
126
138
public function testSanitizeExternal()
127
139
{
128
$initialData = file\_get\_contents('tests/data/externalTest.svg');
129
$expected = file\_get\_contents('tests/data/externalClean.svg');
140
$dataDirectory = \_\_DIR\_\_ . '/data';
141
$initialData = file\_get\_contents($dataDirectory . '/externalTest.svg');
142
$expected = file\_get\_contents($dataDirectory . '/externalClean.svg');
130
143
131
144
$this->class->removeRemoteReferences(true);
…
…
141
154
public function testSanitizeAndMinifiySVGDoc()
142
155
{
143
$initialData = file\_get\_contents('tests/data/svgTestOne.svg');
144
$expected = file\_get\_contents('tests/data/svgCleanOneMinified.svg');
156
$dataDirectory = \_\_DIR\_\_ . '/data';
157
$initialData = file\_get\_contents($dataDirectory . '/svgTestOne.svg');
158
$expected = file\_get\_contents($dataDirectory . '/svgCleanOneMinified.svg');
145
159
146
160
$this->class->minify(true);
…
…
156
170
public function testThatAriaAndDataAttributesAreAllowed()
157
171
{
158
$initialData = file\_get\_contents('tests/data/ariaDataTest.svg');
159
$expected = file\_get\_contents('tests/data/ariaDataClean.svg');
172
$dataDirectory = \_\_DIR\_\_ . '/data';
173
$initialData = file\_get\_contents($dataDirectory . '/ariaDataTest.svg');
174
$expected = file\_get\_contents($dataDirectory . '/ariaDataClean.svg');
160
175
161
176
$this->class->minify(false);
…
…
171
186
public function testThatExternalUseElementsAreStripped()
172
187
{
173
$initialData = file\_get\_contents('tests/data/useTest.svg');
174
$expected = file\_get\_contents('tests/data/useClean.svg');
188
$dataDirectory = \_\_DIR\_\_ . '/data';
189
$initialData = file\_get\_contents($dataDirectory . '/useTest.svg');
190
$expected = file\_get\_contents($dataDirectory . '/useClean.svg');
175
191
176
192
$this->class->minify(false);
…
…
194
210
$this->assertEquals($input, $output);
195
211
}
212
213
/\*\*
214
\* @test
215
\*/
216
public function useRecursionsAreDetected()
217
{
218
$dataDirectory = \_\_DIR\_\_ . '/data';
219
$initialData = file\_get\_contents($dataDirectory . '/xlinkLaughsTest.svg');
220
$expected = file\_get\_contents($dataDirectory . '/xlinkLaughsClean.svg');
221
222
$this->class->minify(false);
223
$cleanData = $this->class->sanitize($initialData);
224
225
$this->assertXmlStringEqualsXmlString($expected, $cleanData);
226
}
227
228
/\*\*
229
\* @test
230
\*/
231
public function infiniteUseLoopsAreDetected()
232
{
233
$dataDirectory = \_\_DIR\_\_ . '/data';
234
$initialData = file\_get\_contents($dataDirectory . '/xlinkLoopTest.svg');
235
$expected = file\_get\_contents($dataDirectory . '/xlinkLoopClean.svg');
236
237
$this->class->minify(false);
238
$cleanData = $this->class->sanitize($initialData);
239
240
$this->assertXmlStringEqualsXmlString($expected, $cleanData);
241
}
196
242
}
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/tests/data/hrefCleanOne.svg
r1192094
r2185438
7
7
<a>test 5</a>
8
8
<a>test 6</a>
9
10
<a>test 7</a>
9
11
</svg>
safe-svg/trunk/lib/vendor/enshrined/svg-sanitize/tests/data/hrefTestOne.svg
r1192094
r2185438
7
7
<a href="data:data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' onload='alert(88)'%3E%3C/svg%3E">test 5</a>
8
8
<a xlink:href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' onload='alert(88)'%3E%3C/svg%3E">test 6</a>
9
10
<a href="javascript	:alert(document.domain)">test 7</a>
9
11
</svg>
safe-svg/trunk/readme.txt
r2130942
r2185438
6
6
Tested up to: 5.2.2
7
7
Requires PHP: 5.6
8
Stable tag: 1.9.4
8
Stable tag: 1.9.5
9
9
License: GPLv2 or later
10
10
License URI: http://www.gnu.org/licenses/gpl-2.0.html
…
…
72
72
73
73
\== Changelog ==
74
75
\= 1.9.5 =
76
\* Underlying library update that fixes some security issues
74
77
75
78
\= 1.9.4 =
safe-svg/trunk/safe-svg.php
r2075207
r2185438
4
4
Plugin URI: https://wpsvg.com/
5
5
Description: Allows SVG uploads into WordPress and sanitizes the SVG before saving it
6
Version: 1.9.4
6
Version: 1.9.5
7
7
Author: Daryll Doyle
8
8
Author URI: http://enshrined.co.uk