harden-react-markdown-urls
v0.0.1
Published
🛡️ Secure wrapper for react-markdown that sanitizes link and image URLs using rehype-harden-urls. Do complex things, the simple way.
Maintainers
Keywords
Readme
harden-react-markdown-urls 🔗🔒
🛡️ A drop-in security wrapper (Higher-Order Component) for react-markdown that automatically sanitizes URLs in your rendered content using the deep cleaning capabilities of rehype-harden-urls.
“Do complex things, the simple way.”
✨ Features
- Full URL Hardening: Protects against malicious links and tracking parameters (like
utm_,fbclid) using robust normalization and strict protocol checking. - Drop-in Integration: Wraps any
react-markdowninstance with zero configuration required. - Seamless Compatibility: Works perfectly alongside existing
rehypePlugins. - Flexible Policies: Fully leverages
rehype-harden-urlspresets (strict,balanced,relaxed) and granular custom options. - Lightweight: Pure functional HOC with minimal overhead.
📦 Installation
We recommend using utilities such as toRegexps, domainsToRegexps, etc. from harden-urls package for creating your custom configurations.
pnpm add harden-react-markdown-urls harden-urlsor
npm install harden-react-markdown-urls harden-urls🧠 Usage
Basic Setup
Wrap your base ReactMarkdown component with hardenReactMarkdown and provide your default security preset.
import ReactMarkdown from "react-markdown";
import { hardenReactMarkdown } from "harden-react-markdown-urls";
import { presets } from "harden-urls/utils";
// 1. Define your default policy (e.g., balanced is a great default)
const HardenedMarkdown = hardenReactMarkdown(ReactMarkdown, presets.balanced);
// 2. Use the wrapped component
function MyComponent({ markdownText }) {
return <HardenedMarkdown>{markdownText}</HardenedMarkdown>;
}👉 Gotcha: Any unsafe link (e.g., [Click me](javascript:alert('xss'))) will have its href attribute removed or be pruned, based on the policy.
Fine-grained Control & Overrides
Use the hardenedOptions prop to override the default policy for a specific instance. This is useful for content sources with different security requirements.
<HardenedMarkdown
// Override the default 'balanced' policy for this instance
hardenedOptions={{
link: { allowedProtocols: new Set(["https:", "mailto:"]) },
image: { allowedProtocols: new Set(["https:"]) },
// Use the callback to log any blocked URLs
onUnsafeUrl: (url, node, type) => console.warn("Blocked:", type, url),
}}>
{markdownText}
</HardenedMarkdown>⚙️ Props
| Prop | Type | Description |
| -------------------------- | ------------------------- | ------------------------------------------------------------------------------------- |
| hardenedOptions | RehypeHardenUrlsOptions | Instance-level override for the hardening policy defined by rehype-harden-urls. |
| All react-markdown props | – | Fully supported and forwarded to the wrapped component. |
⚠️ Best Practice: The Security Stack
For maximum safety when dealing with untrusted Markdown that contains embedded HTML (i.e., when you use rehype-raw), you must pair this package with rehype-sanitize.
The recommended secure chain is:
rehype-raw: Parses raw HTML into the tree.rehype-harden-urls(via this package): Deeply cleans and normalizes all URL values.rehype-sanitize: Provides the final structural guardrail, removing any forbidden tags or attributes.
Always ensure your react-markdown component allows for both rehype-harden-urls and a general sanitizer:
// Example of a minimal safe component
const SafeMarkdown = hardenReactMarkdown(ReactMarkdown, presets.balanced, {
rehypePlugins: [rehypeRaw, rehypeSanitize], // Ensure sanitization is always on top
});⚖️ Why Use This Over Basic Sanitizers?
This package closes critical security gaps often missed by simpler solutions, including Vercel Labs’ older efforts.
| Capability | harden-react-markdown-urls | Vercel Labs' Simple Sanitizers |
| :----------------------------------------------------- | :------------------------------ | :----------------------------- |
| Deep URL Cleaning (Normalization, Case-folding) | ✅ | ❌ |
| Strip Tracking Parameters (utm_, fbclid, etc.) | ✅ | ❌ |
| Hardens Embedded HTML URLs (via rehype-raw) | ✅ (Requires rehype-sanitize) | ⚠️ Incomplete |
| Protocol Validation | ✅ Comprehensive | ⚠️ Basic Prefix Check |
📚 Security Presets
This package utilizes the following presets from rehype-harden-urls for quick configuration:
| Preset | Description | Key Protocols Allowed |
| :--------- | :------------------------------------------------ | :------------------------------------ |
| strict | HTTPS-only, strips all known trackers | https: |
| balanced | Safe default: allows mailto and secure protocols | https:, mailto: |
| relaxed | Allows insecure HTTP, minimal parameter stripping | http:, https:, mailto:, data: |
🤝 Contribution & Support
We enthusiastically welcome contributions from the community!
Whether you are reporting a bug, suggesting a new feature, or submitting a pull request, your help makes this a safer tool for everyone. Please check the GitHub Issues for open tasks.
💖 Adopt and Support: If this package helps secure your application, consider giving us a star on GitHub! You can also sponsor our work to help fund continued development and maintenance.
🪷 License
This project is licensed under the MIT License.
MIT © Mayank Chaudhari
We express gratitude to react-markdown, rehype, and Vercel Labs for the inspiration.
