2 Commits

Author SHA1 Message Date
abite
db27b25372 Merge pull request #56 from gitmotion/fix/escape-html-xss
Add html escaping to frontend uploader for xss security
2025-05-15 12:54:35 -05:00
gitmotion
1835f611da Add html escaping to frontend uploader for xss security
replace innerhtml to textcontent
2025-05-12 13:31:58 -07:00
2 changed files with 22 additions and 10 deletions

12
package-lock.json generated
View File

@@ -1871,9 +1871,9 @@
}
},
"node_modules/nodemon/node_modules/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -2542,9 +2542,9 @@
}
},
"node_modules/simple-update-notifier/node_modules/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {

View File

@@ -88,6 +88,17 @@
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Security helper to escape HTML to prevent XSS
function escapeHtml(text) {
if (!text) return '';
return String(text)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
class FileUploader {
constructor(file, batchId) {
this.file = file;
@@ -288,7 +299,8 @@
const label = document.createElement('div');
label.className = 'progress-label';
label.textContent = this.file.webkitRelativePath || this.file.name;
const fileName = this.file.webkitRelativePath || this.file.name;
label.textContent = escapeHtml(fileName);
const progress = document.createElement('div');
progress.className = 'progress';
@@ -809,7 +821,7 @@
return relativePath.split('/').length === 1;
}).length;
folderItem.innerHTML = `📁 ${folder.name}/ (${formatFileSize(folder.size)} - ${totalFiles} files)`;
folderItem.textContent = `📁 ${escapeHtml(folder.name)}/ (${formatFileSize(folder.size)} - ${totalFiles} files)`;
// Add files in folder
const filesList = document.createElement('div');
@@ -824,7 +836,7 @@
const fileItem = document.createElement('div');
fileItem.className = 'file-item nested';
const relativePath = file.webkitRelativePath.substring(folder.name.length + 1);
fileItem.innerHTML = `📄 ${relativePath} (${formatFileSize(file.size)})`;
fileItem.textContent = `📄 ${escapeHtml(relativePath)} (${formatFileSize(file.size)})`;
filesList.appendChild(fileItem);
});
@@ -846,7 +858,7 @@
.forEach(file => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
fileItem.innerHTML = `📄 ${file.name} (${formatFileSize(file.size)})`;
fileItem.textContent = `📄 ${escapeHtml(file.name)} (${formatFileSize(file.size)})`;
fileList.appendChild(fileItem);
});