remark is a general-purpose tool and, like any tool that processes user-supplied input and produces output that may be rendered in a browser, it comes with security responsibilities. Understanding the attack surfaces — and how to mitigate them — is an important part of deploying remark safely in production. This page covers the three main areas: cross-site scripting (XSS) risks when converting to HTML, denial-of-service (DDoS) risks when handling large or malformed input, and the supply-chain risk introduced by third-party plugins.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/remarkjs/remark/llms.txt
Use this file to discover all available pages before exploring further.
Cross-site scripting (XSS)
Markdown can contain raw HTML. When you convert markdown to HTML, any HTML embedded in the source document is passed through to the output. This means a malicious author can embed<script> tags, javascript: URLs, or event handlers like onerror directly in markdown content. If that output is rendered in a browser without sanitization, it will execute.
The recommended mitigation is to add rehype-sanitize to your unified pipeline immediately before rehype-stringify. It traverses the hast (HTML syntax tree) and removes elements and attributes that are not on its allowlist. The default schema follows GitHub’s sanitization rules:
rehype-sanitize in the chain matters: it must come after remark-rehype (which produces the hast) and before rehype-stringify (which serializes it to an HTML string). Placing it after rehype-stringify would have no effect because the HTML string has already been produced.
If the default sanitization schema is too restrictive or too permissive for your use case, rehype-sanitize accepts a custom schema object. See the rehype-sanitize documentation for details.
DDoS and resource exhaustion
Even without malicious HTML, an attacker can craft markdown that exhausts server resources, causing slowdowns or crashes.Large files
Processing a very large markdown file consumes proportionally large amounts of memory and CPU time. A single multi-megabyte file could tie up a server for seconds. The recommendation is to cap the accepted size of input before it reaches the remark pipeline. According to the remark project’s own guidance, 500 KB is a reasonable upper bound — it is large enough to hold the text of an entire book, yet small enough to prevent runaway processing.Deeply nested structures
Crashes and slowdowns can also originate from smaller payloads. Thousands of deeply nested constructs — such as heavily nested lists, many unclosed link brackets, or large numbers of reference definitions — can cause exponential processing time or stack overflows in the parser. This category of attack is harder to defend against purely by size-capping, because the payload may be small in bytes but expensive to process. The most effective mitigation is to process content in a separate thread or worker so that a runaway parse operation can be terminated without taking down the main application process. In Node.js, you can useworker_threads or a child process with a timeout:
Plugin security
Each plugin you add to a remark pipeline is an additional dependency and a potential attack surface. A plugin runs arbitrary JavaScript with full access to the syntax tree, the virtual file, and any data you have attached to the processor. A compromised or malicious plugin could exfiltrate content, introduce output vulnerabilities, or modify the tree in unexpected ways. Before adding a plugin to your project:- Review the plugin’s source code, especially if it is small and simple enough to audit quickly.
- Check the npm package for known vulnerabilities with
npm audit. - Prefer plugins maintained within the
@remarkjsand@unifiedjsorganizations, which have consistent maintenance and security practices. - Pin your dependency versions and review updates before upgrading.
To report a security vulnerability in remark or any package maintained by the unified collective, follow the security policy in the remarkjs/.github repository. Do not open a public issue for security-sensitive reports.
Summary
XSS
Always use
rehype-sanitize before rehype-stringify when processing untrusted content.DDoS
Cap input size to ~500 KB and process markdown in a worker thread with a timeout.
Plugins
Audit each plugin before adopting it. Prefer packages from the unified collective.
Next steps
Markdown to HTML
See the full pipeline with rehype-sanitize integrated correctly.
Creating Plugins
Understand what plugins can access and do inside the pipeline.