# Long-form descriptions render markdown or HTML correctly; no raw markup shown

- **Pattern:** `ab-001027` (`directory-listing-schema.content-completeness.description-rendering`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001027
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001027)

## Why it matters

Raw markdown or HTML leaking into rendered descriptions is a cross-cutting failure: WCAG 2.2 SC 1.3.1 (Info and Relationships) requires that semantic structure conveyed through presentation be programmatically determinable, and an `<img>` tag or `**bold**` shown as literal characters is unreadable by screen readers. Beyond accessibility, unrendered markup is a OWASP A03 injection surface — if user-supplied HTML is echoed without sanitization, even a markdown renderer can be weaponized via unsanitized `<script>` tags or event-handler attributes. Directories that accept owner-submitted descriptions and pass them directly to `innerHTML` without sanitization are one malicious description away from stored XSS affecting all visitors to that listing page.

## Severity rationale

Low for raw-markup display because the failure is a rendering bug, not an injection vulnerability — but severity escalates to high if the description is rendered via unsanitized `dangerouslySetInnerHTML`.

## Remediation

Render markdown through a sanitizing parser. `react-markdown` is safe by default; if you need raw HTML support, pair `rehype-raw` with `rehype-sanitize` to strip script tags and event handlers.

```tsx
// components/listing/description.tsx
import ReactMarkdown from 'react-markdown';
import rehypeSanitize from 'rehype-sanitize';

export function ListingDescription({ markdown }: { markdown: string }) {
  return (
    <ReactMarkdown rehypePlugins={[rehypeSanitize]}>
      {markdown}
    </ReactMarkdown>
  );
}
```

Never pass raw description strings to `dangerouslySetInnerHTML` without sanitization. If your descriptions are plain-text only, set that as a schema constraint at the database layer and strip formatting characters on write.

## Detection

- **ID:** `description-rendering`
- **Severity:** `low`
- **What to look for:** Enumerate all listing descriptions in the UI. For each, if descriptions allow formatting (markdown, HTML), check a test listing with formatted text. Verify that formatted text is rendered correctly and not shown as raw markup.
- **Pass criteria:** Formatted descriptions (markdown or HTML) are properly parsed and rendered. No raw markup is visible to users — 100% of descriptions must be sanitized against XSS while preserving basic formatting. Report: "X descriptions rendered, all Y properly sanitized and formatted."
- **Fail criteria:** Formatted descriptions show raw `<b>`, `**`, or markdown syntax in the rendered output.
- **Skip (N/A) when:** Descriptions are plain text only.
- **Detail on fail:** Example: `"Description with markdown shows '**Featured Menu**' instead of bold"`
- **Remediation:** Properly parse and render formatted descriptions:

  ```tsx
  import ReactMarkdown from 'react-markdown'

  <ReactMarkdown>{listing.description}</ReactMarkdown>
  ```

## External references

- cwe CWE-79
- owasp A03
- wcag 1.3.1

Taxons: user-experience, injection-and-input-trust

HTML version: https://auditbuffet.com/patterns/ab-001027
