harden-react-markdown-urls
Version:
π‘οΈ Secure wrapper for react-markdown that sanitizes link and image URLs using rehype-harden-urls. Do complex things, the simple way.
163 lines (108 loc) β’ 7.69 kB
Markdown
# harden-react-markdown-urls ππ<img src="https://raw.githubusercontent.com/mayank1513/mayank1513/main/popper.png" style="height: 40px"/>
[](https://github.com/tiny-md/harden-urls/actions/workflows/test.yml)
[](https://codecov.io/gh/tiny-md/harden-urls)
[](https://www.npmjs.com/package/harden-react-markdown-urls)
[](https://www.npmjs.com/package/harden-react-markdown-urls)

[](../../LICENSE)
<p align="center">
<img src="./harden-react-markdown.jpg" alt="harden-react-markdown-urls banner: Secure your Markdown links and images" />
</p>
π‘οΈ A **drop-in security wrapper (Higher-Order Component)** for [`react-markdown`](https://github.com/remarkjs/react-markdown) that automatically sanitizes URLs in your rendered content using the deep cleaning capabilities of [`rehype-harden-urls`](https://github.com/tiny-md/harden-urls/tree/main/libs/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-markdown` instance with zero configuration required.
- **Seamless Compatibility**: Works perfectly alongside existing `rehypePlugins`.
- **Flexible Policies**: Fully leverages `rehype-harden-urls` presets (`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.
```bash
pnpm add harden-react-markdown-urls harden-urls
```
**_or_**
```bash
npm install harden-react-markdown-urls harden-urls
```
## π§ Usage
### Basic Setup
Wrap your base `ReactMarkdown` component with `hardenReactMarkdown` and provide your default security preset.
```tsx
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.
```tsx
<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:
1. **`rehype-raw`**: Parses raw HTML into the tree.
2. **`rehype-harden-urls`** (via this package): Deeply cleans and normalizes all URL **values**.
3. **`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:
```tsx
// 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](https://github.com/tiny-md/harden-urls/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](https://github.com/sponsors/mayank1513) to help fund continued development and maintenance.
## πͺ· License
This project is licensed under the **MIT License**.
MIT Β© [Mayank Chaudhari](https://github.com/mayank1513)
> We express gratitude to **react-markdown**, **rehype**, and **Vercel Labs** for the inspiration.
<p align="center" style="text-align:center">with π by <a href="https://mayank-chaudhari.vercel.app" target="_blank">Mayank Kumar Chaudhari</a></p>