fix(security): Fix XSS vulnerability in handleCustomFeedLogoUpload

Replace innerHTML usage with safe DOM manipulation using createElement
and setAttribute to prevent XSS when injecting uploadedFile.path and
uploadedFile.id values.

- Clear logoCell using textContent instead of innerHTML
- Create all DOM elements using document.createElement
- Set uploadedFile.path and uploadedFile.id via setAttribute (automatically escaped)
- Properly structure DOM tree by appending elements in order
- Prevents malicious HTML/script injection through file path or ID values
This commit is contained in:
Chuck
2026-01-08 12:27:41 -05:00
parent b88842e672
commit c80c23cd08

View File

@@ -4949,23 +4949,59 @@
const pathName = existingPathInput ? existingPathInput.name : `${fullKey}.${index}.logo.path`; const pathName = existingPathInput ? existingPathInput.name : `${fullKey}.${index}.logo.path`;
const idName = existingIdInput ? existingIdInput.name : `${fullKey}.${index}.logo.id`; const idName = existingIdInput ? existingIdInput.name : `${fullKey}.${index}.logo.id`;
logoCell.innerHTML = ` // Clear logoCell and build DOM safely to prevent XSS
<div class="flex items-center space-x-2"> logoCell.textContent = ''; // Clear existing content
<input type="file"
id="${fieldId}_logo_${index}" // Create container div
accept="image/png,image/jpeg,image/bmp" const container = document.createElement('div');
style="display: none;" container.className = 'flex items-center space-x-2';
onchange="handleCustomFeedLogoUpload(event, '${fieldId}', ${index}, '${pluginId}', '${fullKey}')">
<button type="button" // Create file input
onclick="document.getElementById('${fieldId}_logo_${index}').click()" const fileInput = document.createElement('input');
class="px-2 py-1 text-xs bg-gray-200 hover:bg-gray-300 rounded"> fileInput.type = 'file';
<i class="fas fa-upload mr-1"></i> Upload fileInput.id = `${fieldId}_logo_${index}`;
</button> fileInput.accept = 'image/png,image/jpeg,image/bmp';
<img src="/${uploadedFile.path}" alt="Logo" class="w-8 h-8 object-cover rounded border" id="${fieldId}_logo_preview_${index}"> fileInput.style.display = 'none';
<input type="hidden" name="${pathName}" value="${uploadedFile.path}"> fileInput.setAttribute('onchange', `handleCustomFeedLogoUpload(event, '${fieldId}', ${index}, '${pluginId}', '${fullKey}')`);
<input type="hidden" name="${idName}" value="${uploadedFile.id}">
</div> // Create upload button
`; const uploadButton = document.createElement('button');
uploadButton.type = 'button';
uploadButton.className = 'px-2 py-1 text-xs bg-gray-200 hover:bg-gray-300 rounded';
uploadButton.setAttribute('onclick', `document.getElementById('${fieldId}_logo_${index}').click()`);
const uploadIcon = document.createElement('i');
uploadIcon.className = 'fas fa-upload mr-1';
uploadButton.appendChild(uploadIcon);
uploadButton.appendChild(document.createTextNode(' Upload'));
// Create img element - set src via setAttribute to prevent XSS
const img = document.createElement('img');
img.setAttribute('src', `/${uploadedFile.path}`);
img.setAttribute('alt', 'Logo');
img.className = 'w-8 h-8 object-cover rounded border';
img.id = `${fieldId}_logo_preview_${index}`;
// Create hidden input for path - set value via setAttribute to prevent XSS
const pathInput = document.createElement('input');
pathInput.type = 'hidden';
pathInput.setAttribute('name', pathName);
pathInput.setAttribute('value', uploadedFile.path);
// Create hidden input for id - set value via setAttribute to prevent XSS
const idInput = document.createElement('input');
idInput.type = 'hidden';
idInput.setAttribute('name', idName);
idInput.setAttribute('value', String(uploadedFile.id)); // Ensure it's a string
// Append all elements to container
container.appendChild(fileInput);
container.appendChild(uploadButton);
container.appendChild(img);
container.appendChild(pathInput);
container.appendChild(idInput);
// Append container to logoCell
logoCell.appendChild(container);
} }
} else { } else {
alert('Upload failed: ' + (data.message || 'Unknown error')); alert('Upload failed: ' + (data.message || 'Unknown error'));