Skip to content

feat: render description links#22

Merged
JacobCoffee merged 1 commit intomainfrom
render-description-links
Mar 3, 2026
Merged

feat: render description links#22
JacobCoffee merged 1 commit intomainfrom
render-description-links

Conversation

@JacobCoffee
Copy link
Member

Renders description links so #20 doesn't need to happen

image

Copilot AI review requested due to automatic review settings March 3, 2026 17:39
@JacobCoffee JacobCoffee enabled auto-merge (squash) March 3, 2026 17:39
@JacobCoffee JacobCoffee disabled auto-merge March 3, 2026 17:41
@JacobCoffee JacobCoffee merged commit 8811842 into main Mar 3, 2026
5 checks passed
@JacobCoffee JacobCoffee deleted the render-description-links branch March 3, 2026 17:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates how post descriptions are displayed so markdown-style links in frontmatter descriptions render as clickable links (addressing the need described in #20), while keeping meta descriptions plain-text.

Changes:

  • Add renderDescriptionLinks() utility and use it with set:html when rendering descriptions on the home page and blog cards.
  • Add stripDescriptionLinks() utility and apply it in BaseHead.astro to avoid raw markdown link syntax in meta tags.
  • Update imports/usages across affected Astro components.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/pages/index.astro Renders post descriptions via set:html so links can display as anchors.
src/lib/utils.ts Adds helpers to convert/strip markdown-style links in description strings.
src/components/BlogPostCard.astro Renders card descriptions via set:html so links can display as anchors.
src/components/BaseHead.astro Strips markdown link syntax from description before emitting meta tags.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<p class="mt-3 max-w-2xl text-base leading-relaxed text-zinc-600 dark:text-zinc-400 sm:text-lg">
{featured.data.description}
</p>
<p class="mt-3 max-w-2xl text-base leading-relaxed text-zinc-600 dark:text-zinc-400 sm:text-lg" set:html={renderDescriptionLinks(featured.data.description)} />
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using set:html with renderDescriptionLinks(featured.data.description) renders the full description string as raw HTML without any sanitization or escaping. An attacker who can control featured.data.description (e.g., via CMS/content files) can inject arbitrary HTML/JS, including <script> tags or javascript:/attribute-based payloads, leading to XSS in visitors' browsers. To mitigate this, ensure descriptions are safely sanitized/escaped before passing to set:html, or use a markdown/HTML renderer that enforces a strict allowlist of safe tags and URL schemes.

Copilot uses AI. Check for mistakes.
</div>
{post.data.description && (
<p class="mt-2 line-clamp-2 text-sm leading-relaxed text-zinc-500 dark:text-zinc-400">{post.data.description}</p>
<p class="mt-2 line-clamp-2 text-sm leading-relaxed text-zinc-500 dark:text-zinc-400" set:html={renderDescriptionLinks(post.data.description)} />
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using set:html with renderDescriptionLinks(post.data.description) injects description directly into the DOM as HTML, and renderDescriptionLinks only performs a regex replacement without escaping or sanitization. If post.data.description contains attacker-controlled HTML or crafted markdown links (e.g. URLs with quotes or javascript:), this can produce executable script or event handlers and result in XSS. Descriptions should be passed through a robust HTML/markdown sanitizer or safely escaped instead of being rendered directly with set:html.

Copilot uses AI. Check for mistakes.
</div>
{description && (
<p class="mt-1.5 line-clamp-2 text-sm leading-relaxed text-zinc-500 dark:text-zinc-400">{description}</p>
<p class="mt-1.5 line-clamp-2 text-sm leading-relaxed text-zinc-500 dark:text-zinc-400" set:html={renderDescriptionLinks(description)} />
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description prop is rendered via set:html={renderDescriptionLinks(description)}, which outputs raw HTML built from unescaped description text. Because renderDescriptionLinks simply interpolates regex capture groups into an <a href="..."> template, malicious descriptions can inject arbitrary attributes, javascript: URLs, or HTML tags and trigger XSS when the card is viewed or clicked. Use a safe markdown/HTML rendering pipeline that escapes or strips dangerous tags/URL schemes instead of directly injecting the description via set:html.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants