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.