Socket
Socket
Sign inDemoInstall

rehype-sanitize

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rehype-sanitize - npm Package Compare versions

Comparing version 5.0.1 to 6.0.0

lib/index.d.ts

21

index.d.ts

@@ -1,18 +0,3 @@

/**
* Plugin to sanitize HTML.
*
* @type {import('unified').Plugin<[Options?] | Array<void>, Root, Root>}
*/
export default function rehypeSanitize(
options?: void | import('hast-util-sanitize/lib').Schema | undefined
):
| void
| import('unified').Transformer<import('hast').Root, import('hast').Root>
export {defaultSchema} from 'hast-util-sanitize'
export type Root = import('hast').Root
/**
* The sanitation schema defines how and if nodes and properties should be cleaned.
* See `hast-util-sanitize`.
* The default schema is exported as `defaultSchema`.
*/
export type Options = import('hast-util-sanitize').Schema
export { defaultSchema } from "hast-util-sanitize";
export { default } from "./lib/index.js";
export type Options = import('hast-util-sanitize').Schema;
/**
* @typedef {import('hast').Root} Root
*
* @typedef {import('hast-util-sanitize').Schema} Options
* The sanitation schema defines how and if nodes and properties should be cleaned.
* See `hast-util-sanitize`.
* The default schema is exported as `defaultSchema`.
*/
import {sanitize as hastUtilSanitize, defaultSchema} from 'hast-util-sanitize'
/**
* Plugin to sanitize HTML.
*
* @type {import('unified').Plugin<[Options?] | Array<void>, Root, Root>}
*/
export default function rehypeSanitize(options = defaultSchema) {
// @ts-expect-error: assume input `root` matches output root.
return (tree) => hastUtilSanitize(tree, options)
}
export {defaultSchema} from 'hast-util-sanitize'
export {default} from './lib/index.js'
{
"name": "rehype-sanitize",
"version": "5.0.1",
"version": "6.0.0",
"description": "rehype plugin to sanitize HTML",
"license": "MIT",
"keywords": [
"unified",
"clean",
"html",
"plugin",
"rehype",
"rehype-plugin",
"plugin",
"xss",
"sanitize",
"clean",
"html"
"unified",
"xss"
],

@@ -28,5 +28,5 @@ "repository": "rehypejs/rehype-sanitize",

"type": "module",
"main": "index.js",
"types": "index.d.ts",
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts",

@@ -36,46 +36,36 @@ "index.js"

"dependencies": {
"@types/hast": "^2.0.0",
"hast-util-sanitize": "^4.0.0",
"unified": "^10.0.0"
"@types/hast": "^3.0.0",
"hast-util-sanitize": "^5.0.0"
},
"devDependencies": {
"@types/tape": "^4.0.0",
"browserify": "^17.0.0",
"c8": "^7.0.0",
"@types/node": "^20.0.0",
"c8": "^8.0.0",
"deepmerge": "^4.0.0",
"prettier": "^2.0.0",
"rehype": "^12.0.0",
"remark-cli": "^10.0.0",
"prettier": "^3.0.0",
"rehype": "^13.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"rimraf": "^3.0.0",
"tape": "^5.0.0",
"tinyify": "^3.0.0",
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"xo": "^0.47.0"
"typescript": "^5.0.0",
"xo": "^0.56.0"
},
"scripts": {
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix",
"prepack": "npm run build && npm run format",
"test": "npm run build && npm run format && npm run test-coverage",
"test-api": "node --conditions development test.js",
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test.js",
"test": "npm run build && npm run format && npm run test-coverage"
"test-coverage": "c8 --100 --check-coverage --reporter lcov npm run test-api"
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": false,
"singleQuote": true,
"bracketSpacing": false,
"semi": false,
"trailingComma": "none"
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"xo": {
"prettier": true,
"ignores": [
"types/"
]
},
"remarkConfig": {
"plugins": [
"preset-wooorm"
"remark-preset-wooorm"
]

@@ -86,5 +76,8 @@ },

"detail": true,
"strict": true,
"ignoreCatch": true
"ignoreCatch": true,
"strict": true
},
"xo": {
"prettier": true
}
}

@@ -20,3 +20,5 @@ # rehype-sanitize

* [API](#api)
* [`defaultSchema`](#defaultschema)
* [`unified().use(rehypeSanitize[, schema])`](#unifieduserehypesanitize-schema)
* [`Options`](#options)
* [Example](#example)

@@ -57,4 +59,4 @@ * [Example: headings (DOM clobbering)](#example-headings-dom-clobbering)

This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]:
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:

@@ -65,13 +67,13 @@ ```sh

In Deno with [Skypack][]:
In Deno with [`esm.sh`][esmsh]:
```js
import rehypeSanitize from 'https://cdn.skypack.dev/rehype-sanitize@5?dts'
import rehypeSanitize from 'https://esm.sh/rehype-sanitize@6'
```
In browsers with [Skypack][]:
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import rehypeSanitize from 'https://cdn.skypack.dev/rehype-sanitize@5?min'
import rehypeSanitize from 'https://esm.sh/rehype-sanitize@6?bundle'
</script>

@@ -98,22 +100,18 @@ ```

And our module `example.js` looks as follows:
…and our module `example.js` looks as follows:
```js
import {read} from 'to-vfile'
import {unified} from 'unified'
import rehypeParse from 'rehype-parse'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {read} from 'to-vfile'
import {unified} from 'unified'
main()
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeSanitize)
.use(rehypeStringify)
.process(await read('index.html'))
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeSanitize)
.use(rehypeStringify)
.process(await read('index.html'))
console.log(String(file))
}
console.log(String(file))
```

@@ -136,5 +134,11 @@

This package exports the following identifiers: `defaultSchema`.
The default export is `rehypeSanitize`.
This package exports the identifier [`defaultSchema`][api-default-schema].
The default export is [`rehypeSanitize`][api-rehype-sanitize].
### `defaultSchema`
Default schema ([`Options`][api-options]).
Follows GitHub style sanitation.
### `unified().use(rehypeSanitize[, schema])`

@@ -144,11 +148,18 @@

###### `schema`
###### Parameters
Sanitation schema that defines if and how nodes and properties should be
cleaned.
The default schema is exported as `defaultSchema`.
* `options` ([`Options`][api-options], optional)
— configuration
This option is a bit advanced as it requires knowledge of ASTs, so we defer
to the documentation available for [`Schema` in `hast-util-sanitize`][schema].
###### Returns
Transform ([`Transformer`][unified-transformer]).
### `Options`
Schema that defines what nodes and properties are allowed (TypeScript type).
This option is a bit advanced as it requires knowledge of syntax trees, so see
the docs for [`Schema` in `hast-util-sanitize`][hast-util-sanitize-schema].
## Example

@@ -171,12 +182,13 @@

```js
import {promises as fs} from 'node:fs'
import {unified} from 'unified'
/**
* @typedef {import('hast').Root} Root
*/
import fs from 'node:fs/promises'
import rehypeParse from 'rehype-parse'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
main()
async function main() {
const browser = String(await fs.readFile('browser.js'))
const document = `<a name="old"></a>
const browser = String(await fs.readFile('browser.js'))
const document = `<a name="old"></a>
<h1 id="current">Current</h1>

@@ -186,5 +198,9 @@ ${`<p>${'Lorem ipsum dolor sit amet. '.repeat(20)}</p>\n`.repeat(20)}

const file = await unified()
.use(rehypeParse, {fragment: true})
.use(() => (tree) => {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(function () {
/**
* @param {Root} tree
*/
return function (tree) {
tree.children.push({

@@ -196,8 +212,8 @@ type: 'element',

})
})
.use(rehypeStringify)
.process(document)
}
})
.use(rehypeStringify)
.process(document)
await fs.writeFile('output.html', file.value)
}
await fs.writeFile('output.html', String(file))
```

@@ -220,6 +236,7 @@

When you run this code locally, open the generated `output.html`, you can
When you run this code locally and open the generated `output.html`, you can
observe that the links at the bottom work, but also that the `<h1>` element
is printed to the console (the clobbering).
`rehype-sanitize` solved the clobbering by prefixing every `id` and `name`
`rehype-sanitize` solves the clobbering by prefixing every `id` and `name`
attribute with `'user-content-'`.

@@ -234,5 +251,5 @@ Changing `example.js`:

+ .use(rehypeSanitize)
.use(() => (tree) => {
tree.children.push({
type: 'element',
.use(function () {
/**
* @param {Root} tree
```

@@ -249,3 +266,3 @@

But this introduces another problem as the links are now broken.
This introduces another problem as the links are now broken.
It could perhaps be solved by changing all links, but that would make the links

@@ -260,2 +277,5 @@ rather ugly, and we’d need to track what IDs we have outside of the user content

```js
/// <reference lib="dom" />
/* eslint-env browser */
// Page load (you could wrap this in a DOM ready if the script is loaded early).

@@ -271,3 +291,3 @@ hashchange()

'click',
(event) => {
function (event) {
if (

@@ -279,3 +299,3 @@ event.target &&

) {
setTimeout(() => {
setImmediate(function () {
if (!event.defaultPrevented) {

@@ -291,3 +311,3 @@ hashchange()

function hashchange() {
/** @type {string|undefined} */
/** @type {string | undefined} */
let hash

@@ -306,5 +326,5 @@

if (target) {
setTimeout(() => {
setImmediate(function () {
target.scrollIntoView()
}, 0)
})
}

@@ -323,20 +343,16 @@ }

```js
import {unified} from 'unified'
import rehypeKatex from 'rehype-katex'
import rehypeParse from 'rehype-parse'
import rehypeKatex from 'rehype-katex'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
main()
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex)
.use(rehypeSanitize)
.use(rehypeStringify)
.process('<span class="math math-inline">L</span>')
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex)
.use(rehypeSanitize)
.use(rehypeStringify)
.process('<span class="math math-inline">L</span>')
console.log(String(file))
}
console.log(String(file))
```

@@ -358,32 +374,31 @@

@@ -1,7 +1,7 @@
import {unified} from 'unified'
import rehypeKatex from 'rehype-katex'
import rehypeParse from 'rehype-parse'
import rehypeKatex from 'rehype-katex'
-import rehypeSanitize from 'rehype-sanitize'
+import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
main()
@@ -9,8 +9,21 @@ main()
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
+ .use(rehypeSanitize, {
+ ...defaultSchema,
+ attributes: {
+ ...defaultSchema.attributes,
+ div: [
+ ...(defaultSchema.attributes.div || []),
+ ['className', 'math', 'math-display']
+ ],
+ span: [
+ ...(defaultSchema.attributes.span || []),
+ ['className', 'math', 'math-inline']
+ ]
+ }
+ })
.use(rehypeKatex)
- .use(rehypeSanitize)
.use(rehypeStringify)
.process('<span class="math math-inline">L</span>')
const file = await unified()
.use(rehypeParse, {fragment: true})
+ .use(rehypeSanitize, {
+ ...defaultSchema,
+ attributes: {
+ ...defaultSchema.attributes,
+ div: [
+ ...(defaultSchema.attributes.div || []),
+ ['className', 'math', 'math-display']
+ ],
+ span: [
+ ...(defaultSchema.attributes.span || []),
+ ['className', 'math', 'math-inline']
+ ]
+ }
+ })
.use(rehypeKatex)
- .use(rehypeSanitize)
.use(rehypeStringify)
.process('<span class="math math-inline">L</span>')
```

@@ -399,30 +414,26 @@

```js
import {unified} from 'unified'
import rehypeHighlight from 'rehype-highlight'
import rehypeParse from 'rehype-parse'
import rehypeHighlight from 'rehype-highlight'
import rehypeSanitize, {defaultSchema} from './index.js'
import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
main()
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [
...(defaultSchema.attributes.code || []),
// List of all allowed languages:
['className', 'language-js', 'language-css', 'language-md']
]
}
})
.use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [
...(defaultSchema.attributes.code || []),
// List of all allowed languages:
['className', 'language-js', 'language-css', 'language-md']
]
}
})
.use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
console.log(String(file))
}
console.log(String(file))
```

@@ -435,25 +446,24 @@

```diff
async function main() {
const file = await unified()
.use(rehypeParse, {fragment: true})
+ .use(rehypeHighlight, {subset: false})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
- code: [
- ...(defaultSchema.attributes.code || []),
- // List of all allowed languages:
- ['className', 'hljs', 'language-js', 'language-css', 'language-md']
+ span: [
+ ...(defaultSchema.attributes.span || []),
+ // List of all allowed tokens:
+ ['className', 'hljs-addition', 'hljs-attr', 'hljs-attribute', 'hljs-built_in', 'hljs-bullet', 'hljs-char', 'hljs-code', 'hljs-comment', 'hljs-deletion', 'hljs-doctag', 'hljs-emphasis', 'hljs-formula', 'hljs-keyword', 'hljs-link', 'hljs-literal', 'hljs-meta', 'hljs-name', 'hljs-number', 'hljs-operator', 'hljs-params', 'hljs-property', 'hljs-punctuation', 'hljs-quote', 'hljs-regexp', 'hljs-section', 'hljs-selector-attr', 'hljs-selector-class', 'hljs-selector-id', 'hljs-selector-pseudo', 'hljs-selector-tag', 'hljs-string', 'hljs-strong', 'hljs-subst', 'hljs-symbol', 'hljs-tag', 'hljs-template-tag', 'hljs-template-variable', 'hljs-title', 'hljs-type', 'hljs-variable'
const file = await unified()
.use(rehypeParse, {fragment: true})
+ .use(rehypeHighlight, {subset: false})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
- code: [
- ...(defaultSchema.attributes.code || []),
- // List of all allowed languages:
- ['className', 'hljs', 'language-js', 'language-css', 'language-md']
+ span: [
+ ...(defaultSchema.attributes.span || []),
+ // List of all allowed tokens:
+ ['className', 'hljs-addition', 'hljs-attr', 'hljs-attribute', 'hljs-built_in', 'hljs-bullet', 'hljs-char', 'hljs-code', 'hljs-comment', 'hljs-deletion', 'hljs-doctag', 'hljs-emphasis', 'hljs-formula', 'hljs-keyword', 'hljs-link', 'hljs-literal', 'hljs-meta', 'hljs-name', 'hljs-number', 'hljs-operator', 'hljs-params', 'hljs-property', 'hljs-punctuation', 'hljs-quote', 'hljs-regexp', 'hljs-section', 'hljs-selector-attr', 'hljs-selector-class', 'hljs-selector-id', 'hljs-selector-pseudo', 'hljs-selector-tag', 'hljs-string', 'hljs-strong', 'hljs-subst', 'hljs-symbol', 'hljs-tag', 'hljs-template-tag', 'hljs-template-variable', 'hljs-title', 'hljs-type', 'hljs-variable'
+ ]
]
}
})
- .use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
]
}
})
- .use(rehypeHighlight, {subset: false})
.use(rehypeStringify)
.process('<pre><code className="language-js">console.log(1)</code></pre>')
```

@@ -464,12 +474,14 @@

This package is fully typed with [TypeScript][].
It exports an `Options` type, which specifies the interface of the accepted
options.
It exports the additional type [`Options`][api-options].
## Compatibility
Projects maintained by the unified collective are compatible with all maintained
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
As of now, that is Node.js 12.20+, 14.14+, and 16.0+.
Our projects sometimes work with older versions, but this is not guaranteed.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, `rehype-sanitize@^6`,
compatible with Node.js 16.
This plugin works with `rehype-parse` version 3+, `rehype-stringify` version 3+,

@@ -523,5 +535,5 @@ `rehype` version 5+, and `unified` version 6+.

[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-sanitize.svg
[size-badge]: https://img.shields.io/bundlejs/size/rehype-sanitize
[size]: https://bundlephobia.com/result?p=rehype-sanitize
[size]: https://bundlejs.com/?q=rehype-sanitize

@@ -538,4 +550,6 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg

[skypack]: https://www.skypack.dev
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[npm]: https://docs.npmjs.com/cli/install

@@ -555,6 +569,2 @@

[unified]: https://github.com/unifiedjs/unified
[rehype]: https://github.com/rehypejs/rehype
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting

@@ -568,4 +578,6 @@

[schema]: https://github.com/syntax-tree/hast-util-sanitize#schema
[hast-util-sanitize-schema]: https://github.com/syntax-tree/hast-util-sanitize#schema
[rehype]: https://github.com/rehypejs/rehype
[rehype-katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex

@@ -576,1 +588,11 @@

[rehype-highlight]: https://github.com/rehypejs/rehype-highlight
[unified]: https://github.com/unifiedjs/unified
[unified-transformer]: https://github.com/unifiedjs/unified?tab=readme-ov-file#transformer
[api-default-schema]: #defaultschema
[api-options]: #options
[api-rehype-sanitize]: #unifieduserehypesanitize-schema
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc