Skip to content

Commit b75c9dd

Browse files
committed
Fix to sanitize by default
The docs have always said `remark-html` is safe by default. It wasn’t and this patches that. If you do want to be unsafe, use `remark-html` with `sanitize: false`: ```diff -.use(remarkHtml) +.use(remarkHtml, {sanitize: false}) ```
1 parent 3507d99 commit b75c9dd

File tree

2 files changed

+47
-34
lines changed

2 files changed

+47
-34
lines changed

index.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,36 @@ import {toHast} from 'mdast-util-to-hast'
2020
*
2121
* @type {import('unified').Plugin<[Options?]|void[], Root, string>}
2222
*/
23-
export default function remarkHtml(options = {}) {
24-
const handlers = options.handlers || {}
25-
const schema =
26-
options.sanitize && typeof options.sanitize === 'object'
27-
? options.sanitize
28-
: undefined
23+
export default function remarkHtml(settings) {
24+
const options = {...(settings || {})}
25+
/** @type {boolean|undefined} */
26+
let clean
27+
28+
if (typeof options.sanitize === 'boolean') {
29+
clean = options.sanitize
30+
options.sanitize = undefined
31+
}
32+
33+
if (typeof clean !== 'boolean') {
34+
clean = true
35+
}
2936

3037
Object.assign(this, {Compiler: compiler})
3138

3239
/**
3340
* @type {import('unified').CompilerFunction<Root, string>}
3441
*/
3542
function compiler(node, file) {
36-
const hast = toHast(node, {allowDangerousHtml: !options.sanitize, handlers})
43+
const hast = toHast(node, {
44+
allowDangerousHtml: !clean,
45+
handlers: options.handlers
46+
})
3747
// @ts-expect-error: assume root.
38-
const cleanHast = options.sanitize ? sanitize(hast, schema) : hast
48+
const cleanHast = clean ? sanitize(hast, options.sanitize) : hast
3949
const result = toHtml(
4050
// @ts-expect-error: assume root.
4151
cleanHast,
42-
Object.assign({}, options, {allowDangerousHtml: !options.sanitize})
52+
Object.assign({}, options, {allowDangerousHtml: !clean})
4353
)
4454

4555
if (file.extname) {

test/index.js

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@ test('remarkHtml', (t) => {
4141
'should throw when not given a node'
4242
)
4343

44-
let processor = remark().use(remarkHtml)
44+
let processorDangerous = remark().use(remarkHtml, {sanitize: false})
4545

4646
t.equal(
4747
// @ts-expect-error: unknown node.
48-
processor.stringify({type: 'alpha'}),
48+
processorDangerous.stringify({type: 'alpha'}),
4949
'<div></div>',
5050
'should stringify unknown nodes'
5151
)
5252

5353
t.equal(
54-
processor.stringify({
54+
processorDangerous.stringify({
5555
// @ts-expect-error: unknown node.
5656
type: 'alpha',
5757
children: [{type: 'strong', children: [{type: 'text', value: 'bravo'}]}]
@@ -61,7 +61,7 @@ test('remarkHtml', (t) => {
6161
)
6262

6363
t.equal(
64-
processor.stringify({
64+
processorDangerous.stringify({
6565
// @ts-expect-error: unknown node.
6666
type: 'alpha',
6767
children: [{type: 'text', value: 'bravo'}],
@@ -75,7 +75,8 @@ test('remarkHtml', (t) => {
7575
'should stringify unknown nodes'
7676
)
7777

78-
processor = remark().use(remarkHtml, {
78+
processorDangerous = remark().use(remarkHtml, {
79+
sanitize: false,
7980
handlers: {
8081
/** @param {Paragraph} node */
8182
paragraph(h, node) {
@@ -91,12 +92,12 @@ test('remarkHtml', (t) => {
9192
})
9293

9394
t.equal(
94-
processor.processSync('paragraph text').toString(),
95+
processorDangerous.processSync('paragraph text').toString(),
9596
'<p>changed</p>\n',
9697
'should allow overriding handlers'
9798
)
9899

99-
processor = remark()
100+
processorDangerous = remark()
100101
.use(
101102
/** @type {import('unified').Plugin<void[], Root>} */
102103
() => (ast) => {
@@ -106,31 +107,33 @@ test('remarkHtml', (t) => {
106107
}
107108
}
108109
)
109-
.use(remarkHtml)
110+
.use(remarkHtml, {sanitize: false})
110111

111112
t.equal(
112-
processor.processSync('![hello](example.jpg "overwritten")').toString(),
113+
processorDangerous
114+
.processSync('![hello](example.jpg "overwritten")')
115+
.toString(),
113116
'<p><img src="example.jpg" alt="hello" title="overwrite"></p>\n',
114117
'should patch and merge attributes'
115118
)
116119

117-
processor = remark()
120+
processorDangerous = remark()
118121
.use(
119122
/** @type {import('unified').Plugin<void[], Root>} */
120123
() => (ast) => {
121124
// @ts-expect-error: assume it exists.
122125
ast.children[0].children[0].data = {hName: 'b'}
123126
}
124127
)
125-
.use(remarkHtml)
128+
.use(remarkHtml, {sanitize: false})
126129

127130
t.equal(
128-
processor.processSync('**Bold!**').toString(),
131+
processorDangerous.processSync('**Bold!**').toString(),
129132
'<p><b>Bold!</b></p>\n',
130133
'should overwrite a tag-name'
131134
)
132135

133-
processor = remark()
136+
processorDangerous = remark()
134137
.use(
135138
/** @type {import('unified').Plugin<void[], Root>} */
136139
() => (ast) => {
@@ -149,15 +152,15 @@ test('remarkHtml', (t) => {
149152
}
150153
}
151154
)
152-
.use(remarkHtml)
155+
.use(remarkHtml, {sanitize: false})
153156

154157
t.equal(
155-
processor.processSync('`var`').toString(),
158+
processorDangerous.processSync('`var`').toString(),
156159
'<p><code><span class="token">var</span></code></p>\n',
157160
'should overwrite content'
158161
)
159162

160-
processor = remark()
163+
processorDangerous = remark()
161164
.use(
162165
/** @type {import('unified').Plugin<void[], Root>} */
163166
() => (ast) => {
@@ -179,12 +182,12 @@ test('remarkHtml', (t) => {
179182
.use(remarkHtml, {sanitize: true})
180183

181184
t.equal(
182-
processor.processSync('`var`').toString(),
185+
processorDangerous.processSync('`var`').toString(),
183186
'<p><code>var</code></p>\n',
184187
'should not overwrite content in `sanitize` mode'
185188
)
186189

187-
processor = remark()
190+
processorDangerous = remark()
188191
.use(
189192
/** @type {import('unified').Plugin<void[], Root>} */
190193
() => (ast) => {
@@ -193,10 +196,10 @@ test('remarkHtml', (t) => {
193196
}
194197
}
195198
)
196-
.use(remarkHtml)
199+
.use(remarkHtml, {sanitize: false})
197200

198201
t.equal(
199-
processor.processSync('```js\nvar\n```\n').toString(),
202+
processorDangerous.processSync('```js\nvar\n```\n').toString(),
200203
'<pre><code class="foo">var\n</code></pre>\n',
201204
'should overwrite classes on code'
202205
)
@@ -206,8 +209,8 @@ test('remarkHtml', (t) => {
206209
.use(remarkHtml)
207210
.processSync('## Hello <span>world</span>')
208211
.toString(),
209-
'<h2>Hello <span>world</span></h2>\n',
210-
'should be `sanitation: false` by default'
212+
'<h2>Hello world</h2>\n',
213+
'should be `sanitation: true` by default'
211214
)
212215

213216
t.equal(
@@ -224,7 +227,7 @@ test('remarkHtml', (t) => {
224227
.use(remarkHtml, {sanitize: null})
225228
.processSync('## Hello <span>world</span>')
226229
.toString(),
227-
'<h2>Hello <span>world</span></h2>\n',
230+
'<h2>Hello world</h2>\n',
228231
'should support sanitation: null'
229232
)
230233

@@ -294,7 +297,7 @@ test('CommonMark', (t) => {
294297

295298
const actual = unified()
296299
.use(remarkParse)
297-
.use(remarkHtml)
300+
.use(remarkHtml, {sanitize: false})
298301
.processSync(example.markdown)
299302
.toString()
300303

@@ -337,7 +340,7 @@ test('Integrations', (t) => {
337340
const result = remark()
338341
// @ts-expect-error: fine.
339342
.use(integrationMap[name])
340-
.use(remarkHtml)
343+
.use(remarkHtml, {sanitize: false})
341344
.processSync(file)
342345
.toString()
343346

0 commit comments

Comments
 (0)