From d4258c8f2a5f3ae65bd6d6138119afa6dc5f2f2a Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Mon, 16 Mar 2026 15:45:45 -0700 Subject: [PATCH 1/4] fix: [AI-194] pre-release security and resource cleanup fixes for tracing - Escape `t.summary.status` with `e()` in trace viewer HTML to prevent XSS - Add SIGINT/SIGTERM handlers to gracefully stop trace viewer server on Ctrl+C - Log snapshot write failures with `console.debug` instead of silently swallowing Closes #194 Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/src/altimate/observability/tracing.ts | 3 ++- packages/opencode/src/altimate/observability/viewer.ts | 2 +- packages/opencode/src/cli/cmd/trace.ts | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/altimate/observability/tracing.ts b/packages/opencode/src/altimate/observability/tracing.ts index f67eb70f3c..d58dd678f2 100644 --- a/packages/opencode/src/altimate/observability/tracing.ts +++ b/packages/opencode/src/altimate/observability/tracing.ts @@ -627,7 +627,8 @@ export class Tracer { this.snapshotPromise = fs.mkdir(this.snapshotDir, { recursive: true }) .then(() => fs.writeFile(tmpPath, JSON.stringify(trace, null, 2))) .then(() => fs.rename(tmpPath, filePath)) - .catch(() => { + .catch((err) => { + console.debug(`[tracing] failed to write trace snapshot: ${err}`) fs.unlink(tmpPath).catch(() => {}) }) .finally(() => { diff --git a/packages/opencode/src/altimate/observability/viewer.ts b/packages/opencode/src/altimate/observability/viewer.ts index f262fe7fb8..609f4ec988 100644 --- a/packages/opencode/src/altimate/observability/viewer.ts +++ b/packages/opencode/src/altimate/observability/viewer.ts @@ -197,7 +197,7 @@ tagsHtml += 'Provider: ' + e(t.metadata.providerId || tagsHtml += 'Model: ' + e(model) + ''; tagsHtml += 'Agent: ' + e(t.metadata.agent || 'default') + ''; var stColor = t.summary.status === 'error' || t.summary.status === 'crashed' ? 'var(--red)' : t.summary.status === 'running' ? 'var(--orange)' : 'var(--green)'; -tagsHtml += 'Status: ' + (t.summary.status || 'unknown') + ''; +tagsHtml += 'Status: ' + e(t.summary.status || 'unknown') + ''; ${live ? "tagsHtml += 'LIVE';" : ""} document.getElementById('tags').innerHTML = tagsHtml; diff --git a/packages/opencode/src/cli/cmd/trace.ts b/packages/opencode/src/cli/cmd/trace.ts index 76aaacb80f..6469ce523c 100644 --- a/packages/opencode/src/cli/cmd/trace.ts +++ b/packages/opencode/src/cli/cmd/trace.ts @@ -210,6 +210,14 @@ export const TraceCommand = cmd({ // User can open manually } + // Graceful shutdown on interrupt + const shutdown = () => { + server.stop() + process.exit(0) + } + process.on("SIGINT", shutdown) + process.on("SIGTERM", shutdown) + // Keep server alive until interrupted await new Promise(() => {}) } From ec8c6e53eeba0040a2d515a546130b01c017888c Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Mon, 16 Mar 2026 16:00:48 -0700 Subject: [PATCH 2/4] fix: comprehensive XSS hardening for trace viewer HTML Systematically escape all user-controllable fields in `viewer.ts`: - Escape `span.kind` and `span.status` in detail panel, waterfall, tree, and log views - Escape `span.spanId` in `data-sid` attributes - Coerce all numeric fields with `Number()` to prevent string injection via `.toLocaleString()` - Add single-quote escaping (`'`) to the `e()` function for defense-in-depth Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/altimate/observability/viewer.ts | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/opencode/src/altimate/observability/viewer.ts b/packages/opencode/src/altimate/observability/viewer.ts index 609f4ec988..6eec3d0d63 100644 --- a/packages/opencode/src/altimate/observability/viewer.ts +++ b/packages/opencode/src/altimate/observability/viewer.ts @@ -183,7 +183,7 @@ pre.io { background: var(--bg); border: 1px solid var(--border); border-radius: