diff --git a/app/components/Readme.vue b/app/components/Readme.vue index cfdb1ffe51..bfe67bf7b2 100644 --- a/app/components/Readme.vue +++ b/app/components/Readme.vue @@ -89,6 +89,7 @@ function handleClick(event: MouseEvent) { min-width: 0; /* Contain all children z-index values inside this container */ isolation: isolate; + contain: layout paint; } /* README headings - styled by visual level (data-level), not semantic level */ diff --git a/server/utils/readme.ts b/server/utils/readme.ts index 81dddfbb28..e78f9a51b3 100644 --- a/server/utils/readme.ts +++ b/server/utils/readme.ts @@ -198,9 +198,9 @@ const ALLOWED_ATTR: Record = { 'blockquote': ['data-callout'], 'details': ['open'], 'code': ['class'], - 'pre': ['class', 'style'], + 'pre': ['class'], 'span': ['class', 'style'], - 'div': ['class', 'style', 'align'], + 'div': ['class', 'align'], 'p': ['align'], } @@ -609,8 +609,8 @@ ${html} // Resolve image URLs (with GitHub blob → raw conversion) renderer.image = ({ href, title, text }: Tokens.Image) => { const resolvedHref = resolveImageUrl(href, packageName, repoInfo) - const titleAttr = title ? ` title="${title}"` : '' - const altAttr = text ? ` alt="${text}"` : '' + const titleAttr = title ? ` title="${escapeHtml(title)}"` : '' + const altAttr = text ? ` alt="${escapeHtml(text)}"` : '' return `` } @@ -687,6 +687,13 @@ ${html} allowedTags: ALLOWED_TAGS, allowedAttributes: ALLOWED_ATTR, allowedSchemes: ['http', 'https', 'mailto'], + // disallow styles other than the ones shiki emits + allowedStyles: { + span: { + 'color': [/^#[0-9a-f]{3,8}$/i], + '--shiki-light': [/^#[0-9a-f]{3,8}$/i], + }, + }, // Transform img src URLs (GitHub blob → raw, relative → GitHub raw) transformTags: { // Headings are already processed to correct semantic levels by processHeading()