mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-30 05:23:24 +00:00
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 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> * export: preserve doctype and comments in stripRemoteImages 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> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f3ccc6c718
commit
492b158d93
4 changed files with 146 additions and 1 deletions
|
|
@ -163,7 +163,13 @@ exports.doExport = async (req: any, res: any, padId: string, readOnlyId: string,
|
|||
// for the temp path token (see matching note in ImportHandler.ts).
|
||||
const randNum = crypto.randomBytes(16).toString('hex');
|
||||
const srcFile = `${tempDirectory}/etherpad_export_${randNum}.html`;
|
||||
await fsp_writeFile(srcFile, html);
|
||||
// Strip remote <img> tags before handing the document to LibreOffice.
|
||||
// soffice fetches remote image URLs during conversion, so any plugin/hook
|
||||
// that injects an <img src="http://..."> into export HTML would otherwise
|
||||
// turn export into a blind SSRF sink. The native path already does this
|
||||
// (see stripRemoteImages above); apply it here so both paths match.
|
||||
const {stripRemoteImages} = require('../utils/ExportSanitizeHtml');
|
||||
await fsp_writeFile(srcFile, stripRemoteImages(html));
|
||||
|
||||
// ensure html can be collected by the garbage collector
|
||||
html = null;
|
||||
|
|
|
|||
|
|
@ -208,6 +208,17 @@ export const stripRemoteImages = (html: string): string => {
|
|||
if (VOID_TAGS.has(name)) return;
|
||||
out += `</${name}>`;
|
||||
},
|
||||
// Preserve document-level directives (notably `<!doctype html>`) and
|
||||
// comments. stripRemoteImages() runs on the FULL export document for the
|
||||
// soffice path, so dropping the doctype would flip LibreOffice into quirks
|
||||
// mode. htmlparser2 surfaces the doctype as a processing instruction whose
|
||||
// `data` is e.g. `!doctype html`.
|
||||
onprocessinginstruction(name, data) {
|
||||
out += `<${data}>`;
|
||||
},
|
||||
oncomment(data) {
|
||||
out += `<!--${data}-->`;
|
||||
},
|
||||
}, {decodeEntities: false, lowerCaseTags: true});
|
||||
parser.write(html);
|
||||
parser.end();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue