diff --git a/AGENTS.md b/AGENTS.md index ce7909f2bd..bf238ddd1f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -188,6 +188,7 @@ yarn test:shared # All shared code tests ## Security - Sanitize all user input. +- Always use `sanitizeUrl()` when setting `href` or `src` from user-controlled data in ProseMirror `toDOM` methods, regardless of whether it is imported via an alias or a relative path. Unlike React components, `toDOM` writes raw DOM and does not sanitize attribute values. - Use CSRF protection. - Use rateLimiter middleware for sensitive endpoints. - Follow OWASP guidelines. diff --git a/shared/editor/nodes/Mention.tsx b/shared/editor/nodes/Mention.tsx index 84fbba5f56..77a015b41f 100644 --- a/shared/editor/nodes/Mention.tsx +++ b/shared/editor/nodes/Mention.tsx @@ -1,4 +1,5 @@ import isMatch from "lodash/isMatch"; +import { sanitizeUrl } from "../../utils/urls"; import type { Token } from "markdown-it"; import type { NodeSpec, @@ -105,7 +106,7 @@ export default class Mention extends Node { ? `${env.URL}/doc/${node.attrs.modelId}` : node.attrs.type === MentionType.Collection ? `${env.URL}/collection/${node.attrs.modelId}` - : node.attrs.href, + : sanitizeUrl(node.attrs.href), "data-type": node.attrs.type, "data-id": node.attrs.modelId, "data-actorid": node.attrs.actorId, @@ -113,7 +114,7 @@ export default class Mention extends Node { node.attrs.type === MentionType.PullRequest || node.attrs.type === MentionType.Issue || node.attrs.type === MentionType.Project - ? node.attrs.href + ? sanitizeUrl(node.attrs.href) : `mention://${node.attrs.id}/${node.attrs.type}/${node.attrs.modelId}`, "data-unfurl": JSON.stringify(node.attrs.unfurl), },