Security hardening: setting scopes, workspace-confined agent fs access, permission matching - #1
Conversation
Promote the 1.0.1 release: GUI-launch PATH/ENOENT fix, model-cache EPERM fix, in-place tool-call streaming, ACP agent registry browser, VSIX packaging cleanup, and publish CI/CD for the VS Code Marketplace and Open VSX. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s, permission matching - Scope sigit.agents, sigit.agent.default, sigit.registry.url, and sigit.permission.mode as machine settings so a workspace's .vscode/settings.json can no longer inject an arbitrary agent command, flip the permission mode to allow, or point the registry at a malicious catalog. - Declare untrustedWorkspaces/virtualWorkspaces capabilities so the extension stays disabled in Restricted Mode instead of silently spawning agents. - Confine the agent's fs/read_text_file and fs/write_text_file channel to the workspace folders; paths outside the workspace now follow sigit.permission.mode (allow / deny / modal prompt) instead of being granted unconditionally. - Classify permission options by the ACP kind field first; the previous unanchored name regex let agent-chosen labels like "Allow now" match /no/ and be auto-selected as the deny option (and vice versa). The name fallback is now word-bounded. - Reject in-flight JSON-RPC requests when the agent closes the connection, so a crashed agent no longer leaves the chat stuck busy. - Cap the ndjson read buffer at 16 MiB and truncate unparseable lines in error messages. - Honor the ACP line/limit parameters in fs/read_text_file instead of always returning the whole file. - Generate the webview CSP nonce with crypto.randomBytes instead of Math.random. - Run the registry parser test in CI alongside smoke and webview tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDM1YxP1jqcjSGpcXwKtwG
There was a problem hiding this comment.
Security hardening across the extension. Config keys (sigit.agents, sigit.agent.default, sigit.registry.url, sigit.permission.mode) become machine-scoped so workspaces can't override them, and untrusted/virtual workspace capabilities are declared. The ACP Connection now fails in-flight requests on close, caps the read buffer at 16 MiB, and truncates unparseable lines. chatView.ts confines agent fs read/write to workspace folders (falling back to permission.mode), classifies permission options by ACP kind before a word-bounded name regex, honors read line/limit params, and uses crypto.randomBytes for the CSP nonce.
Reviewers should check the isInWorkspace path-containment logic and the read line/limit slicing for off-by-one and symlink edge cases.
Automated review by siGit Code · commit 2e06c39
| if (typeof line === "number" || typeof limit === "number") { | ||
| const lines = text.split("\n"); | ||
| const start = typeof line === "number" ? Math.max(0, line - 1) : 0; | ||
| const end = typeof limit === "number" ? start + limit : lines.length; |
There was a problem hiding this comment.
warning — limit is applied as a line count from start, but ACP limit is typically a byte or character limit, not a line count; confirm the semantics match the spec, otherwise agents get wrong content.
| const folders = vscode.workspace.workspaceFolders ?? []; | ||
| return folders.some((folder) => { | ||
| const rel = path.relative(folder.uri.fsPath, uri.fsPath); | ||
| return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel)); |
There was a problem hiding this comment.
warning — isInWorkspace compares resolved fsPaths but doesn't resolve symlinks; a symlink inside the workspace pointing outside (or a path with symlinked ancestors) can bypass the confinement check.
|
|
||
| private onData(text: string): void { | ||
| this.buffer += text; | ||
| if (this.buffer.length > Connection.MAX_BUFFER_LENGTH && !this.buffer.includes("\n")) { |
There was a problem hiding this comment.
nit — The buffer cap only triggers when there is no newline at all; an agent streaming many small valid lines plus one huge unterminated tail could still accumulate up to 16 MiB per chunk boundary, which is acceptable but the guard won't fire until the whole buffer lacks a newline.
sigit.permission.mode as machine settings so a workspace's
.vscode/settings.json can no longer inject an arbitrary agent command,
flip the permission mode to allow, or point the registry at a
malicious catalog.
extension stays disabled in Restricted Mode instead of silently
spawning agents.
to the workspace folders; paths outside the workspace now follow
sigit.permission.mode (allow / deny / modal prompt) instead of being
granted unconditionally.
unanchored name regex let agent-chosen labels like "Allow now" match
/no/ and be auto-selected as the deny option (and vice versa). The
name fallback is now word-bounded.
connection, so a crashed agent no longer leaves the chat stuck busy.
in error messages.
always returning the whole file.
Math.random.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01YDM1YxP1jqcjSGpcXwKtwG