Harden Hermes webview and launch trust flow#1
Merged
Conversation
Copilot created this pull request from a session on behalf of
gitricko
May 22, 2026 09:56
View session
There was a problem hiding this comment.
Pull request overview
Hardens the Hermes VS Code extension against local/UI injection surfaces by tightening the trust boundary around launching the Hermes binary, strengthening webview escaping behavior, and upgrading sanitization-related dependencies.
Changes:
- Replace CSP nonce generation with cryptographic randomness in the webview HTML template.
- Escape additional user-/agent-controlled labels before inserting into
innerHTMLin the webview UI. - Remove the pre-trust
hermes --versionprobe and bumpdompurifyto^3.4.5(lockfile refreshed accordingly).
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/webview/renderers.ts | Adds HTML escaping for tool history rendering to reduce injected markup risk. |
| src/webview/menus.ts | Escapes session/skill metadata before rendering into dropdown HTML. |
| src/webview/main.ts | Escapes tool labels and attachment chip names before inserting into the chat DOM. |
| src/htmlTemplate.ts | Switches CSP nonce generation from Math.random() to crypto.randomBytes(). |
| src/extension.ts | Removes the activation-time Hermes version probe and stops sending version at startup. |
| package.json | Upgrades dompurify dependency to ^3.4.5. |
| package-lock.json | Updates resolved dompurify version and lockfile metadata to match. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+145
to
+149
| const cleaned = DOMPurify.sanitize(m.text.replace(/^[✓✗⋯]\s*/, '')); | ||
| const colonIdx = cleaned.indexOf(':'); | ||
| const name = colonIdx > 0 ? cleaned.slice(0, colonIdx).trim() : cleaned; | ||
| const detail = colonIdx > 0 ? `<span class="tool-detail">${cleaned.slice(colonIdx + 1).trim()}</span>` : ''; | ||
| toolEl.innerHTML = `<span class="tool-status${cls}">${icon}</span><span class="tool-name">${name}</span>${detail}`; | ||
| const detail = colonIdx > 0 ? `<span class="tool-detail">${escapeHtml(cleaned.slice(colonIdx + 1).trim())}</span>` : ''; | ||
| toolEl.innerHTML = `<span class="tool-status${cls}">${icon}</span><span class="tool-name">${escapeHtml(name)}</span>${detail}`; |
Comment on lines
+11
to
+18
| function escapeHtml(value: string): string { | ||
| return value | ||
| .replace(/&/g, '&') | ||
| .replace(/</g, '<') | ||
| .replace(/>/g, '>') | ||
| .replace(/"/g, '"') | ||
| .replace(/'/g, '''); | ||
| } |
Comment on lines
250
to
256
| const panel = new ChatPanelProvider( | ||
| context.extensionUri, | ||
| session, | ||
| hermesModel, | ||
| hermesVersion, | ||
| '', | ||
| context, | ||
| line => outputChannel.appendLine(line), |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
gitricko
approved these changes
May 22, 2026
gitricko
approved these changes
May 22, 2026
Owner
|
@copilot resolve the merge conflicts in this pull request |
gitricko
approved these changes
May 22, 2026
Comment on lines
405
to
+409
| const toolEl = appendDiv(messagesEl, 'msg tool'); | ||
| if (msg.toolCallId) toolEl.dataset.toolId = msg.toolCallId; | ||
| const { label, info } = formatToolDisplay(msg.toolName ?? '', msg.toolKind, msg.toolLocations, msg.toolDetail); | ||
| const infoHtml = info ? `<span class="tool-detail">${DOMPurify.sanitize(info)}</span>` : ''; | ||
| toolEl.innerHTML = `<span class="tool-status${statusClass}">${statusIcon}</span><span class="tool-name">${label}</span>${infoHtml}`; | ||
| const infoHtml = info ? `<span class="tool-detail">${escapeHtml(info)}</span>` : ''; | ||
| toolEl.innerHTML = `<span class="tool-status${statusClass}">${statusIcon}</span><span class="tool-name">${escapeHtml(label)}</span>${infoHtml}`; |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment on lines
+336
to
+339
| const hermesVersion = readHermesVersion(hermesPath); | ||
| if (hermesVersion) { | ||
| panel.updateVersion(hermesVersion); | ||
| } |
- Add caching for hermesVersion and hermesPath to avoid repeated blocking calls - Only call readHermesVersion() when client is not running or hermesPath changed - Prevents event loop blocking on repeated ensureConnected() invocations - Fixes discussion_r3289407691
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
gitricko
approved these changes
May 22, 2026
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| } | ||
|
|
||
| updateVersion(version: string): void { | ||
| if (!version || version === this.hermesVersion) return; |
Comment on lines
+338
to
355
| // Only read version if client is not already running or if hermesPath changed | ||
| // to avoid repeated blocking calls on every ensureConnected() invocation | ||
| if (!client.running || lastHermesPathForVersion !== hermesPath) { | ||
| const hermesVersion = readHermesVersion(hermesPath); | ||
| lastHermesPathForVersion = hermesPath; | ||
| if (hermesVersion) { | ||
| cachedHermesVersion = hermesVersion; | ||
| } else { | ||
| cachedHermesVersion = ''; | ||
| } | ||
| } | ||
| if (cachedHermesVersion) { | ||
| panel.updateVersion(cachedHermesVersion); | ||
| } else { | ||
| panel.updateVersion(''); | ||
| } | ||
| client.setHermesPath(hermesPath); | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This patch closes a few local attack surfaces in the Hermes VS Code extension: it removes a pre-trust binary probe, hardens webview rendering against injected markup, and updates the sanitization dependency to a fixed release.
Trust boundary
hermes --versionbefore the binary is trusted.Webview sanitization
innerHTML.Dependency hardening
dompurifyto3.4.5.CSP hardening
Math.random()nonce generation with cryptographic randomness.Example: