DEV Community

Tapas Mahanta
Tapas Mahanta

Posted on

🔐 Fixing an XSS Vulnerability in a Quill-Based HTML Export Pipeline

While contributing to an open-source project built on top of Quill, I discovered and fixed a Cross-Site Scripting (XSS) vulnerability in its HTML export functionality.

Although this issue surfaced in a specific project, the root cause is relevant to anyone working with Quill or similar rich-text editors, especially when exporting user content as HTML.

This post covers:
• what went wrong,
• how the vulnerability could be exploited,
• and how it was fixed without breaking backward compatibility.

🚨 The Problem: Unsafe HTML Export

The project exposes a method to export editor content as semantic HTML, roughly like:

const html = quill.getSemanticHTML();

This is a common pattern in Quill-based systems — exporting editor content for:
• documentation
• previews
• dashboards
• emails

The issue was that user-controlled content was rendered into HTML without proper escaping in some export paths.

As a result, carefully crafted input could lead to arbitrary JavaScript execution when the exported HTML was rendered.

🧨 Attack Surface

The vulnerability affected two specific Quill embed formats.

1️⃣ Formula embeds
• Formula values were rendered directly into HTML
• No escaping was applied
• Malicious LaTeX-like input could inject raw HTML / JavaScript

2️⃣ Video embeds
• Video URLs were embedded into:
• href attributes
• visible text content
• URLs were not escaped
• Crafted input could break out of attributes and inject scripts

💥 Example Exploit

quill.insertEmbed(
0,
'formula',
'alert(document.cookie)'
);

const html = quill.getSemanticHTML();
// ❌ Script tag ends up unescaped in the HTML output

This creates a stored XSS scenario — particularly risky when exported HTML is later rendered in trusted contexts.

🛠️ The Fix

The fix was intentionally minimal and conservative, following Quill’s existing architecture:
• Escape all HTML special characters before rendering user-controlled content
• Apply escaping consistently to:
• formula values
• video URLs (both attributes and text nodes)
• Reuse the project’s existing escapeText() utility instead of introducing new sanitizers

Escaped characters include:

& < > ' "

This ensures user input can never be interpreted as executable markup during export.

🧪 Testing & Verification

To validate the fix, I added 14 focused security tests covering both embed types.

The tests verify prevention of:
• HTML tag injection
• Attribute injection
• Quote breaking
• Event handler injection

Results:
• ✅ All existing tests pass
• ✅ No runtime behavior changes
• ✅ No API changes

📦 Security Details
• CVE: CVE-2025-15056
• CWE: CWE-79 (Improper Neutralization of Input During Web Page Generation)
• Severity: Low
• Affected versions: ≤ 2.0.3
• Patched versions: Provided by this fix

The fix is suitable for a security patch release and can be safely backported.

🤝 Final Thoughts

Open-source security work doesn’t always involve complex exploits or cryptography.
Often, it’s about carefully examining trust boundaries — especially where user content crosses from data into markup.

If you maintain or build on top of Quill and:
• export editor content as HTML,
• render exported HTML in user-facing systems,
• or build custom embeds,

…it’s worth auditing those paths carefully.

Thanks for reading 🙌
Happy to discuss similar issues or review HTML export pipelines.

Top comments (1)

Collapse
 
tapas100 profile image
Tapas Mahanta

Happy to discuss similar issues or review HTML export pipelines in rich-text editors. Feedback welcome.