security(export): strip remote images on the soffice path to match the native path#8071
security(export): strip remote images on the soffice path to match the native path#8071JohnMcLear wants to merge 2 commits into
Conversation
…e native path Defense-in-depth / consistency fix — not a core vulnerability on its own. Core Etherpad never emits <img> tags in export HTML; they only appear when a plugin/hook injects them, so sanitising such content is primarily the injecting plugin's responsibility. However, the native in-process export path (issue #7538) already calls stripRemoteImages() defensively, while the LibreOffice (soffice) path wrote the HTML to the temp file verbatim. soffice is the only export path that actually performs outbound fetches for remote <img> URLs during conversion, so a plugin-injected remote image there becomes a blind SSRF sink. This makes the soffice path consistent with the native path core already ships. Adds a regression test that injects a remote image via exportHTMLAdditionalContent, intercepts the temp file via the exportConvert hook, and asserts no remote image URL survives. Remote-image behaviour reported privately by meifukun. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
PR Summary by QodoHarden soffice export by stripping remote sources (SSRF defense-in-depth)
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
There was a problem hiding this comment.
Pull request overview
This PR hardens the LibreOffice (soffice) export conversion path by stripping remote <img> URLs from the HTML written to the temporary file, matching the existing defense-in-depth behavior already used by the native in-process export path. This reduces the risk of blind SSRF via plugin-injected export HTML when soffice performs outbound fetches during conversion.
Changes:
- Apply the existing
stripRemoteImages()sanitizer to the HTML written to thesofficetemp input file. - Add a backend regression test that injects a remote image via
exportHTMLAdditionalContent, captures the temp HTML viaexportConvert, and asserts the remote URL is removed.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/node/handler/ExportHandler.ts | Sanitizes HTML with stripRemoteImages() before writing the soffice conversion temp file. |
| src/tests/backend/specs/sofficeExportRemoteImage.ts | Adds a regression test ensuring remote image URLs do not reach the soffice converter input HTML. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Code Review by Qodo
1.
|
Addresses Qodo review on #8071. Applying stripRemoteImages() to the full export document for the soffice path dropped `<!doctype html>` and HTML comments, because the htmlparser2 handler only emitted open/text/close tags. A missing doctype can flip LibreOffice's HTML import into quirks mode, subtly changing rendering for all soffice exports. Add onprocessinginstruction (doctype) and oncomment handlers so the serializer round-trips document directives and comments while still stripping remote images. The native path is unaffected (it strips only extractBody() output, which has no doctype). Adds regression tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @qodo-free-for-open-source-projects — valid. Running |
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
| // mode. htmlparser2 surfaces the doctype as a processing instruction whose | ||
| // `data` is e.g. `!doctype html`. | ||
| onprocessinginstruction(name, data) { | ||
| out += `<${data}>`; | ||
| }, |
Defense-in-depth / consistency fix — not a core vulnerability on its own. Core Etherpad never emits
<img>tags in export HTML; they only appear when a plugin/hook injects them, so sanitising such content is primarily the injecting plugin's responsibility.However, the native in-process export path (#7538) already calls
stripRemoteImages()defensively, while the LibreOffice (soffice) path wrote the export HTML to the temp file verbatim.sofficeis the only export path that performs outbound fetches for remote<img>URLs during conversion, so a plugin-injected remote image there becomes a blind SSRF sink. This change makes thesofficepath consistent with the native path core already ships.Change
One line: apply the existing
stripRemoteImages(html)before writing the soffice temp file.Test
New
sofficeExportRemoteImage.tsregression test injects a remote image viaexportHTMLAdditionalContent, intercepts the temp file via theexportConverthook, and asserts no remote image URL survives. Existing 54 export tests still pass;tsc --noEmitclean.Remote-image behaviour reported privately by meifukun (https://github.com/meifukun). No security advisory is filed for this — it is hardening, not a core vuln.
🤖 Generated with Claude Code