Skip to content

Commit 26ae34d

Browse files
committed
fix: bind dashboard to loopback-only and escape HTML in trace rendering to prevent data exposure and XSS
1 parent e85554a commit 26ae34d

2 files changed

Lines changed: 15 additions & 8 deletions

File tree

dashboard/index.html

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,20 @@ <h1>Promptimprover Swarm Dashboard</h1>
3535
const tr = document.createElement('tr');
3636
const fmtTime = new Date(log.timestamp).toLocaleTimeString();
3737
const reason = log.reasoning_path && log.reasoning_path.length > 60 ? log.reasoning_path.slice(0,57) + '...' : log.reasoning_path;
38+
const escapeHtml = (unsafe) => (unsafe || '').toString()
39+
.replace(/&/g, "&amp;")
40+
.replace(/</g, "&lt;")
41+
.replace(/>/g, "&gt;")
42+
.replace(/"/g, "&quot;")
43+
.replace(/'/g, "&#039;");
44+
3845
tr.innerHTML = `
39-
<td>${fmtTime}</td>
40-
<td>${log.span_id || 'N/A'}</td>
41-
<td>${log.persona || 'Unknown'}</td>
42-
<td>${log.action_type || 'Unknown'}</td>
43-
<td>${log.metrics?.total_tokens || 0}</td>
44-
<td>${reason || ''}</td>
46+
<td>${escapeHtml(fmtTime)}</td>
47+
<td>${escapeHtml(log.span_id || 'N/A')}</td>
48+
<td>${escapeHtml(log.persona || 'Unknown')}</td>
49+
<td>${escapeHtml(log.action_type || 'Unknown')}</td>
50+
<td>${escapeHtml(log.metrics?.total_tokens || 0)}</td>
51+
<td>${escapeHtml(reason || '')}</td>
4552
`;
4653
tbody.appendChild(tr);
4754
});

dashboard/server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ const server = http.createServer(async (req, res) => {
5656
}
5757
});
5858

59-
server.listen(PORT, () => {
60-
console.log(`Promptimprover dashboard listening on http://localhost:${PORT}`);
59+
server.listen(PORT, '127.0.0.1', () => {
60+
console.log(`Promptimprover dashboard listening on http://127.0.0.1:${PORT}`);
6161
});

0 commit comments

Comments
 (0)