Escape the OpenGraph image URL in link previews

Pasting a link builds the preview by interpolating the unfurled metadata
into an HTML string. The image URL went into src="..." unescaped, so a
page whose og:image carries a double quote closes the attribute early and
everything after it becomes attributes on the preview's img element.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
This commit is contained in:
Rosa Gutierrez
2026-09-11 16:00:07 +02:00
committed by Rosa Gutierrez
parent ef147d17db
commit c1ad057db8
4 changed files with 134 additions and 4 deletions
+6
View File
@@ -1,3 +1,5 @@
const HTML_ESCAPES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", "\"": "&quot;", "'": "&#39;" }
export function truncateString(string, length, omission = "…") {
if (string.length <= length) {
return string
@@ -5,3 +7,7 @@ export function truncateString(string, length, omission = "…") {
return string.slice(0, length - omission.length) + omission
}
}
export function escapeHTML(string) {
return String(string).replace(/[&<>"']/g, character => HTML_ESCAPES[character])
}
@@ -1,5 +1,5 @@
import { post } from "@rails/request.js"
import { truncateString } from "helpers/string_helpers"
import { escapeHTML, truncateString } from "helpers/string_helpers"
const UNFURLED_TWITTER_AVATAR_CSS_CLASS = "cf-twitter-avatar"
const TWITTER_AVATAR_URL_PREFIX = "https://pbs.twimg.com/profile_images"
@@ -68,7 +68,7 @@ export default class OpengraphEmbedOperation {
<div class="og-embed__description">${truncateString(embed.description, 560)}</div>
</div>
<div class="og-embed__image">
<img src="${embed.image}" class="image" alt="" />
<img src="${escapeHTML(embed.image)}" class="image" alt="" />
</div>
</div>
</actiontext-opengraph-embed>`