Security: Fix XSS vulnerabilities in dashboard templates and improve mobile test UI safety

This commit is contained in:
AlexanderWhitestone
2026-02-26 02:07:54 -05:00
parent 3792bf16cf
commit 930ec9eb80
10 changed files with 241 additions and 19 deletions

View File

@@ -0,0 +1,19 @@
# Self-Modify Report: 20260226_070455
**Instruction:** Add docstring
**Target files:** src/foo.py
**Dry run:** True
**Backend:** ollama
**Branch:** N/A
**Result:** SUCCESS
**Error:** none
**Commit:** none
**Attempts:** 1
**Autonomous cycles:** 0
## Attempt 1 -- dry_run
### LLM Response
```
llm raw
```

View File

@@ -0,0 +1,31 @@
# Self-Modify Report: 20260226_070455
**Instruction:** Break it
**Target files:** src/foo.py
**Dry run:** False
**Backend:** ollama
**Branch:** N/A
**Result:** FAILED
**Error:** Tests failed after 1 attempt(s).
**Commit:** none
**Attempts:** 1
**Autonomous cycles:** 0
## Attempt 1 -- complete
### LLM Response
```
llm raw
```
### Edits Written
#### src/foo.py
```python
x = 1
```
### Test Result: FAILED
```
1 failed
```

View File

@@ -0,0 +1,12 @@
# Self-Modify Report: 20260226_070455
**Instruction:** do something vague
**Target files:** (auto-detected)
**Dry run:** False
**Backend:** ollama
**Branch:** N/A
**Result:** FAILED
**Error:** No target files identified. Specify target_files or use more specific language.
**Commit:** none
**Attempts:** 0
**Autonomous cycles:** 0

View File

@@ -0,0 +1,31 @@
# Self-Modify Report: 20260226_070455
**Instruction:** Fix foo
**Target files:** src/foo.py
**Dry run:** False
**Backend:** ollama
**Branch:** N/A
**Result:** FAILED
**Error:** Tests failed after 1 attempt(s).
**Commit:** none
**Attempts:** 1
**Autonomous cycles:** 0
## Attempt 1 -- complete
### LLM Response
```
llm raw
```
### Edits Written
#### src/foo.py
```python
x = 2
```
### Test Result: FAILED
```
FAILED
```

View File

@@ -0,0 +1,34 @@
# Self-Modify Report: 20260226_070455
**Instruction:** Fix foo
IMPORTANT CORRECTION from previous failure:
Fix: do X instead of Y
**Target files:** src/foo.py
**Dry run:** False
**Backend:** ollama
**Branch:** N/A
**Result:** SUCCESS
**Error:** none
**Commit:** abc123
**Attempts:** 1
**Autonomous cycles:** 0
## Attempt 1 -- complete
### LLM Response
```
llm raw
```
### Edits Written
#### src/foo.py
```python
x = 2
```
### Test Result: PASSED
```
PASSED
```

View File

@@ -343,15 +343,41 @@
const pct = TOTAL ? Math.round((passed / TOTAL) * 100) : 0;
const color = failed > 0 ? "var(--red)" : "var(--green)";
summaryBody.innerHTML = `
<div class="mt-summary-score" style="color:${color}">${passed} / ${TOTAL}</div>
<div class="mt-summary-pct">${pct}% pass rate</div>
<div style="margin-top:16px;">
<div class="mt-summary-row"><span>PASSED</span><span style="color:var(--green);font-weight:700;">${passed}</span></div>
<div class="mt-summary-row"><span>FAILED</span><span style="color:var(--red);font-weight:700;">${failed}</span></div>
<div class="mt-summary-row"><span>SKIPPED</span><span style="color:var(--amber);font-weight:700;">${skipped}</span></div>
</div>
`;
// Safely build summary UI using DOM API to avoid XSS from potentially untrusted variables
summaryBody.innerHTML = '';
const scoreDiv = document.createElement('div');
scoreDiv.className = 'mt-summary-score';
scoreDiv.style.color = color;
scoreDiv.textContent = passed + ' / ' + TOTAL;
summaryBody.appendChild(scoreDiv);
const pctDiv = document.createElement('div');
pctDiv.className = 'mt-summary-pct';
pctDiv.textContent = pct + '% pass rate';
summaryBody.appendChild(pctDiv);
const statsContainer = document.createElement('div');
statsContainer.style.marginTop = '16px';
const createRow = (label, value, colorVar) => {
const row = document.createElement('div');
row.className = 'mt-summary-row';
const labelSpan = document.createElement('span');
labelSpan.textContent = label;
const valSpan = document.createElement('span');
valSpan.style.color = 'var(--' + colorVar + ')';
valSpan.style.fontWeight = '700';
valSpan.textContent = value;
row.appendChild(labelSpan);
row.appendChild(valSpan);
return row;
};
statsContainer.appendChild(createRow('PASSED', passed, 'green'));
statsContainer.appendChild(createRow('FAILED', failed, 'red'));
statsContainer.appendChild(createRow('SKIPPED', skipped, 'amber'));
summaryBody.appendChild(statsContainer);
const statusMsg = document.createElement('p');
statusMsg.style.marginTop = '12px';

View File

@@ -1,18 +1,18 @@
<div class="chat-message user">
<div class="msg-meta" style="color:var(--orange);">YOU // {{ timestamp }}</div>
<div class="msg-body" style="border-color:var(--border-glow);">{{ message }}</div>
<div class="msg-body" style="border-color:var(--border-glow);">{{ message | e }}</div>
</div>
{% if response %}
<div class="chat-message agent">
<div class="msg-meta" style="color:var(--purple);">{{ agent.name | upper }} // {{ timestamp }}</div>
<div class="msg-body" style="border-left:3px solid var(--purple);">{{ response }}</div>
<div class="msg-body" style="border-left:3px solid var(--purple);">{{ response | e }}</div>
</div>
{% elif error %}
<div class="chat-message error-msg">
<div class="msg-meta">SYSTEM // {{ timestamp }}</div>
<div class="msg-body" style="border-left:3px solid var(--red); color:var(--red);">{{ error }}</div>
<div class="msg-body" style="border-left:3px solid var(--red); color:var(--red);">{{ error | e }}</div>
</div>
{% elif task_id %}

View File

@@ -7,9 +7,9 @@
<div class="card-header mc-panel-header d-flex justify-content-between align-items-center">
<span>
<span class="status-dot {{ dot }}" style="margin-right:6px;"></span>
// {{ agent.name | upper }}
// {{ agent.name | upper | e }}
<span style="font-size:10px; color:var(--text-dim); margin-left:10px; letter-spacing:.1em;">
{{ agent.capabilities or "no capabilities listed" }}
{{ agent.capabilities | e or "no capabilities listed" }}
</span>
</span>
<button class="mc-btn-clear"
@@ -31,9 +31,9 @@
TASK · {{ task.status.value | upper }} · {{ task.created_at[:19].replace("T"," ") }}
</div>
<div class="msg-body" style="border-left: 3px solid var(--{% if task.status.value == 'completed' %}green{% elif task.status.value == 'failed' %}red{% else %}orange{% endif %});">
<div style="color:var(--text-dim); font-size:11px; margin-bottom:4px;">{{ task.description }}</div>
<div style="color:var(--text-dim); font-size:11px; margin-bottom:4px;">{{ task.description | e }}</div>
{% if task.result %}
<div style="color:var(--text-bright);">{{ task.result }}</div>
<div style="color:var(--text-bright);">{{ task.result | e }}</div>
{% endif %}
</div>
</div>
@@ -57,7 +57,7 @@
<input type="text"
name="message"
class="form-control mc-input"
placeholder="send a message to {{ agent.name | lower }}..."
placeholder="send a message to {{ agent.name | lower | e }}..."
autocomplete="off"
autocorrect="off"
autocapitalize="none"

View File

@@ -13,7 +13,7 @@
<div class="d-flex align-items-center gap-2 mb-1">
<span class="status-dot {{ dot }}"></span>
<span class="agent-name" style="font-size:13px;">{{ agent.name | upper }}</span>
<span class="agent-name" style="font-size:13px;">{{ agent.name | upper | e }}</span>
</div>
<div class="agent-meta" style="margin-bottom:8px;">
@@ -21,7 +21,7 @@
<span class="meta-val">{{ agent.status }}</span><br>
{% if agent.capabilities %}
<span class="meta-key">CAPS</span>
<span class="meta-val" style="font-size:10px;">{{ agent.capabilities }}</span><br>
<span class="meta-val" style="font-size:10px;">{{ agent.capabilities | e }}</span><br>
{% endif %}
<span class="meta-key">SEEN</span>
<span class="meta-val" style="font-size:10px;">{{ agent.last_seen[:19].replace("T"," ") if agent.last_seen else "—" }}</span>

View File

@@ -0,0 +1,69 @@
import pytest
from fastapi.templating import Jinja2Templates
def test_agent_chat_msg_xss_prevention():
"""Verify XSS prevention in agent_chat_msg.html."""
templates = Jinja2Templates(directory="src/dashboard/templates")
payload = "<script>alert('xss')</script>"
class MockAgent:
def __init__(self):
self.name = "TestAgent"
self.id = "test-agent"
response = templates.get_template("partials/agent_chat_msg.html").render({
"message": payload,
"response": payload,
"error": payload,
"agent": MockAgent(),
"timestamp": "12:00:00"
})
# Check that payload is escaped
assert "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" in response
assert payload not in response
def test_agent_panel_xss_prevention():
"""Verify XSS prevention in agent_panel.html."""
templates = Jinja2Templates(directory="src/dashboard/templates")
payload = "<script>alert('xss')</script>"
class MockAgent:
def __init__(self):
self.name = payload
self.id = "test-agent"
self.status = "idle"
self.capabilities = payload
class MockTask:
def __init__(self):
self.id = "task-1"
self.status = type('obj', (object,), {'value': 'completed'})
self.created_at = "2026-02-26T12:00:00"
self.description = payload
self.result = payload
response = templates.get_template("partials/agent_panel.html").render({
"agent": MockAgent(),
"tasks": [MockTask()]
})
assert "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" in response
assert payload not in response
def test_swarm_sidebar_xss_prevention():
"""Verify XSS prevention in swarm_agents_sidebar.html."""
templates = Jinja2Templates(directory="src/dashboard/templates")
payload = "<script>alert('xss')</script>"
class MockAgent:
def __init__(self):
self.name = payload
self.id = "test-agent"
self.status = "idle"
self.capabilities = payload
self.last_seen = "2026-02-26T12:00:00"
response = templates.get_template("partials/swarm_agents_sidebar.html").render({
"agents": [MockAgent()]
})
assert "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" in response
assert payload not in response