Harden Stellar CLI plugin sanitization against markdown/HTML injection#2537
Harden Stellar CLI plugin sanitization against markdown/HTML injection#2537fnando wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens generation of the Docusaurus MDX page for the Stellar CLI plugins list by escaping attacker-controlled GitHub repository fields (name/description) so they render as inert literal text rather than Markdown/HTML/MDX syntax.
Changes:
- Replaces the old
sanitize()(limited HTML escaping) with a newescape()that collapses whitespace and entity-escapes a broad set of Markdown/HTML control characters. - Applies the escaping to both
item.full_name(link text) anditem.descriptionin the generated MDX content.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Preview is available here: |
|
Preview is available here: |
|
Hello @fnando , I discovered this Stored XSS vulnerability and reported it on June 19, 2026 at 10:24 AM UTC — 6 days before this PR was opened. I am Haq Nawaz (GitHub: @haqnawaz03329-debug). My report included the vulnerable code at scripts/stellar_cli_plugins.mjs:14-16, a proof-of-concept repository (haqnawaz03329-debug/haqnawaz) tagged with stellar-cli-plugin containing an XSS payload in the description, and the GitHub API endpoint serving it. I also submitted this through HackerOne, which is still pending review. https://hackerone.com/reports/3812437 |
|
@fnando ? |
GitHub repo names and descriptions surfaced on the CLI plugins list are attacker-controlled — anyone can tag a repo with the
stellar-cli-plugintopic — and they're injected into an MDX file that Docusaurus renders as markdown + HTML/JSX. The previoussanitize()only escaped& < > { }, which stopped HTML/JSX injection but left markdown injection wide open: a description could inject phishing links, remote tracking images, fake headings, code fences, or other block-level structure.This replaces
sanitize()withescape(), which renders these values as inert literal text:import/exportinjection, which only fire at the start of a line.& < > " ' * _ \[ ] ( ) # + - . ! | ~ \ { } = : $`) via a lookup map, so none of them are parsed as syntax on Docusaurus's render pass.Applied to both the plugin
full_name(link text) and the free-formdescription.