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.
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`.
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.
// 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.
ID: directory-listing-schema.content-completeness.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:
import ReactMarkdown from 'react-markdown'
<ReactMarkdown>{listing.description}</ReactMarkdown>