Skip to content

Commit f5c2a0f

Browse files
author
Yuriy Bezsonov
committed
fix(security): replace innerHTML with DOM APIs for file upload preview
Use createElement/textContent instead of innerHTML with user input (file.name) to eliminate XSS through DOM vulnerability. Resolves code scanning alerts #41-46.
1 parent b30e7e2 commit f5c2a0f

6 files changed

Lines changed: 96 additions & 18 deletions

File tree

samples/quality-assurance/ai-agent/src/main/resources/templates/chat-working.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

samples/quality-assurance/ai-agent/src/main/resources/templates/chat.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

samples/security/apikey/ai-agent/src/main/resources/templates/chat-working.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

samples/security/apikey/ai-agent/src/main/resources/templates/chat.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

samples/security/oauth/ai-agent/src/main/resources/templates/chat-working.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

samples/security/oauth/ai-agent/src/main/resources/templates/chat.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,28 @@ <h1 class="text-3xl font-bold text-dev-accent">🤖 AI Agent</h1>
341341
messageDiv.innerHTML = `
342342
<div class="ml-auto flex">
343343
<div class="message-bubble-user rounded-lg p-3 max-w-3xl">
344-
<button class="copy-button" data-copy-text="File attached: ${escapeHtml(file.name)}">📋</button>
345-
<p class="text-light-text dark:text-dev-text mb-2">📎 File attached: ${escapeHtml(file.name)}</p>
346-
<img src="${imageUrl}" alt="${escapeHtml(file.name)}" class="max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition" onclick="openImageModal('${imageUrl}')" />
347344
</div>
348345
<div class="w-10 h-10 rounded-full bg-dev-secondary bg-opacity-20 flex items-center justify-center ml-3">
349346
<span class="text-lg">👤</span>
350347
</div>
351348
</div>
352349
`;
350+
const bubble = messageDiv.querySelector('.message-bubble-user');
351+
const copyBtn = document.createElement('button');
352+
copyBtn.className = 'copy-button';
353+
copyBtn.dataset.copyText = 'File attached: ' + file.name;
354+
copyBtn.textContent = '📋';
355+
bubble.appendChild(copyBtn);
356+
const p = document.createElement('p');
357+
p.className = 'text-light-text dark:text-dev-text mb-2';
358+
p.textContent = '📎 File attached: ' + file.name;
359+
bubble.appendChild(p);
360+
const img = document.createElement('img');
361+
img.src = imageUrl;
362+
img.alt = file.name;
363+
img.className = 'max-w-full max-h-64 rounded border border-light-border dark:border-dev-border cursor-pointer hover:opacity-80 transition';
364+
img.addEventListener('click', function() { openImageModal(imageUrl); });
365+
bubble.appendChild(img);
353366
messageContainer.appendChild(messageDiv);
354367
messageContainer.scrollTop = messageContainer.scrollHeight;
355368
}

0 commit comments

Comments
 (0)