惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
V
Visual Studio Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Threatpost
TaoSecurity Blog
TaoSecurity Blog
Engineering at Meta
Engineering at Meta
T
Troy Hunt's Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Heimdal Security Blog
Webroot Blog
Webroot Blog
A
About on SuperTechFans
S
Securelist
Recorded Future
Recorded Future
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
P
Palo Alto Networks Blog
F
Fortinet All Blogs
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
W
WeLiveSecurity
N
Netflix TechBlog - Medium
博客园 - 叶小钗
宝玉的分享
宝玉的分享
大猫的无限游戏
大猫的无限游戏
G
GRAHAM CLULEY
Schneier on Security
Schneier on Security
博客园 - 聂微东
www.infosecurity-magazine.com
www.infosecurity-magazine.com
小众软件
小众软件
博客园 - 【当耐特】
有赞技术团队
有赞技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
A
Arctic Wolf
C
CXSECURITY Database RSS Feed - CXSecurity.com
Google DeepMind News
Google DeepMind News
Security Latest
Security Latest
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Spread Privacy
Spread Privacy
罗磊的独立博客
The Hacker News
The Hacker News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
IT之家
IT之家
B
Blog
GbyAI
GbyAI
Hugging Face - Blog
Hugging Face - Blog
Google Online Security Blog
Google Online Security Blog
MongoDB | Blog
MongoDB | Blog

Streamdown Documentation

Configuration FAQ Getting Started Introduction Security Animation Carets Code Blocks Components GitHub Flavored Markdown Interactivity Internationalization Memoization Migrate from react-markdown Styling Unterminated Block Parsing Typography Usage @streamdown/cjk @streamdown/code Built-in Plugins @streamdown/math @streamdown/mermaid Custom renderers
Link Safety
Vercel · 2026-04-11 · via Streamdown Documentation

Configurable confirmation modal for external links to protect users from malicious URLs.

When rendering AI-generated or user-generated content, links can pose security risks. The link safety feature adds a confirmation modal before opening external links, similar to ChatGPT's implementation.

Link safety is enabled by default. When a user clicks any link, a confirmation modal appears with:

  • The full URL being opened
  • A "Copy link" button
  • An "Open link" button
  • Close via backdrop click or Escape key

To disable the confirmation modal and allow links to open directly:

import { Streamdown } from 'streamdown';

export default function Chat({ content }) {
  return (
    <Streamdown linkSafety={{ enabled: false }}>
      {content}
    </Streamdown>
  );
}

Use the onLinkCheck callback to allow trusted domains without showing the modal:

<Streamdown
  linkSafety={{
    enabled: true,
    onLinkCheck: (url) => {
      // Return true to allow without modal (safelist)
      // Return false to show confirmation modal
      return url.startsWith('https://your-app.com') ||
             url.startsWith('https://github.com');
    }
  }}
>
  {content}
</Streamdown>

The callback receives the URL and can return:

  • true - Open the link directly without modal
  • false - Show the confirmation modal
  • Promise<boolean> - Async checks are supported

Async Safelist Check

For server-side safelist validation:

<Streamdown
  linkSafety={{
    enabled: true,
    onLinkCheck: async (url) => {
      const response = await fetch('/api/check-url', {
        method: 'POST',
        body: JSON.stringify({ url }),
      });
      const { isSafe } = await response.json();
      return isSafe;
    }
  }}
>
  {content}
</Streamdown>

Replace the default modal with your own component using renderModal:

import { Streamdown, type LinkSafetyModalProps } from 'streamdown';

function CustomLinkModal({ url, isOpen, onClose, onConfirm }: LinkSafetyModalProps) {
  if (!isOpen) return null;

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <h2>External Link</h2>
        <p>You're about to visit:</p>
        <code>{url}</code>
        <div className="actions">
          <button onClick={onClose}>Cancel</button>
          <button onClick={onConfirm}>Continue</button>
        </div>
      </div>
    </div>
  );
}

export default function Chat({ content }) {
  return (
    <Streamdown
      linkSafety={{
        enabled: true,
        renderModal: (props) => <CustomLinkModal {...props} />,
      }}
    >
      {content}
    </Streamdown>
  );
}

The renderModal function receives:

PropTypeDescription
urlstringThe URL being opened
isOpenbooleanWhether the modal is visible
onClose() => voidCall to close the modal
onConfirm() => voidCall to open the link and close the modal

Link safety works alongside content hardening. Use both for comprehensive protection:

import { Streamdown, defaultRehypePlugins } from 'streamdown';
import { harden } from 'rehype-harden';

export default function SecureChat({ content }) {
  return (
    <Streamdown
      linkSafety={{
        enabled: true,
        onLinkCheck: (url) => url.startsWith('https://trusted.com'),
      }}
      rehypePlugins={[
        defaultRehypePlugins.raw,
        [
          harden,
          {
            allowedLinkPrefixes: [
              'https://trusted.com',
              'https://github.com',
            ],
            allowedProtocols: ['https', 'mailto'],
          },
        ],
      ]}
    >
      {content}
    </Streamdown>
  );
}

This provides two layers of protection:

  1. Content hardening - Blocks or rewrites disallowed URLs at render time
  2. Link safety modal - Requires user confirmation before navigation

Import the types for custom modal implementations:

import type { LinkSafetyConfig, LinkSafetyModalProps } from 'streamdown';

const config: LinkSafetyConfig = {
  enabled: true,
  onLinkCheck: (url) => url.startsWith('https://safe.com'),
  renderModal: (props: LinkSafetyModalProps) => <CustomModal {...props} />,
};

LinkSafetyConfig

PropertyTypeDefaultDescription
enabledbooleantrueEnable link interception and modal
onLinkCheck(url: string) => boolean | Promise<boolean>-Optional safelist callback
renderModal(props: LinkSafetyModalProps) => ReactNode-Optional custom modal component

LinkSafetyModalProps

PropertyTypeDescription
urlstringThe URL to be opened
isOpenbooleanModal visibility state
onClose() => voidClose the modal without navigation
onConfirm() => voidConfirm and open the link