Compare commits

...

1 Commits

Author SHA1 Message Date
google-labs-jules[bot] 5f530a28b3 Fix DOM-based XSS in upload.js by sanitizing file.name
This commit resolves a DOM-based Cross-Site Scripting (XSS) vulnerability in `frontend/static/js/upload.js`. Previously, the user-controlled `file.name` was directly interpolated into the DOM using `innerHTML` without any HTML entity escaping. A maliciously crafted filename could lead to script execution.

A local `_escapeHtml` function has been introduced to safely escape characters like `<`, `>`, `&`, `"`, and `'` before rendering.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-05-29 03:02:29 +00:00
2 changed files with 16 additions and 1 deletions
+4
View File
@@ -28,3 +28,7 @@
**Vulnerability:** The `/process-url` endpoint used `httpx.AsyncClient(follow_redirects=True)` after validating the initial user-provided URL against SSRF protections. However, it did not validate the target URLs of any subsequent HTTP redirects, allowing an attacker to provide a safe URL that redirects to an internal/private IP, bypassing the security check.
**Learning:** Initial URL validation is insufficient when the HTTP client is configured to follow redirects automatically. The client must be explicitly configured to validate every redirect target.
**Prevention:** When using `httpx.AsyncClient(follow_redirects=True)` for user-provided URLs, always implement a redirect validator hook function (e.g., using `event_hooks={'response': [validate_redirect]}`) that resolves the `Location` header and passes it through the same SSRF validation logic before the redirect is followed.
## 2026-05-29 - DOM-based XSS in Upload UI
**Vulnerability:** In `frontend/static/js/upload.js`, user-controlled file names (`file.name`) were directly injected into the DOM via `innerHTML` without sanitization, leading to a potential DOM-based Cross-Site Scripting (XSS) vulnerability.
**Learning:** Any user-controlled input, including file names, that is dynamically inserted into HTML (specifically via `innerHTML` or similar sinks) must be treated as untrusted and sanitized.
**Prevention:** Always define and use a local `_escapeHtml` function to sanitize user-controlled strings (replacing `&`, `<`, `>`, `"`, `'`) before interpolating them into HTML strings that will be rendered via `innerHTML`.
+12 -1
View File
@@ -293,13 +293,24 @@ function processFiles(files, progressContainer, statusMessage) {
updateStatus();
}
function _escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
// Pre-create one progress row per file.
const queueItems = fileArray.map((file) => {
const row = document.createElement('div');
row.className = 'flex flex-col mb-2';
const escapedName = _escapeHtml(file.name);
row.innerHTML = `
<div class="flex justify-between">
<span class="text-sm truncate" title="${file.name}">${file.name}</span>
<span class="text-sm truncate" title="${escapedName}">${escapedName}</span>
<span class="text-xs text-gray-500">${formatFileSize(file.size)}</span>
</div>
<div class="w-full bg-gray-200 h-2 rounded-full mt-1">