Skip to content

Commit c751e3e

Browse files
topcoder1claude
andcommitted
fix(mini-app): use JSON.stringify for JS-string context in task-detail
ISSUE-002 (HIGH): `const taskId = '${escapeHtml(data.taskId)}'` escapes HTML (& < > ") but NOT single quote — wrong escape domain for a JS string literal. A taskId containing ' or \n breaks out of the string and injects arbitrary JS. email-full.ts already uses the correct JSON.stringify pattern; task-detail had drifted. ISSUE-008 (MED): `data.status.toUpperCase()` was rendered unescaped. TS's 'active'|'blocked'|'complete' union is a type assertion at the DB boundary (server.ts:315), not runtime-validated — a corrupted row could inject HTML. Wrap in escapeHtml. Also wrap the taskId in encodeURIComponent when building the SSE URL so it survives special characters that JSON.stringify passes through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 988062c commit c751e3e

1 file changed

Lines changed: 3 additions & 3 deletions

File tree

src/mini-app/templates/task-detail.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export function renderTaskDetail(data: TaskDetailData): string {
6969
</head>
7070
<body data-updated-at="${escapeHtml(data.startedAt)}">
7171
<div class="header">
72-
<div class="status">${data.status.toUpperCase()}</div>
72+
<div class="status">${escapeHtml(String(data.status).toUpperCase())}</div>
7373
<div class="title">${escapeHtml(data.title)}</div>
7474
</div>
7575
<div style="margin-bottom:16px;">${stepsHtml}</div>
@@ -79,8 +79,8 @@ export function renderTaskDetail(data: TaskDetailData): string {
7979
<button class="btn" style="color:#f85149;">Abort</button>
8080
</div>
8181
<script>
82-
const taskId = '${escapeHtml(data.taskId)}';
83-
const evtSource = new EventSource('/api/task/' + taskId + '/stream');
82+
const taskId = ${JSON.stringify(data.taskId)};
83+
const evtSource = new EventSource('/api/task/' + encodeURIComponent(taskId) + '/stream');
8484
8585
evtSource.onmessage = function(event) {
8686
const state = JSON.parse(event.data);

0 commit comments

Comments
 (0)