Can you do a security audit on this vscode extension?

HEAD
16a0dc4bump version

do a security audit on this vscode extension

Avatar of anthropic/claude-opus-4.6
Claude Opus 4.6
commented

I've now reviewed the entire codebase. Here is my comprehensive security audit:


#🔒 Security Audit: copy VS Code Extension (v1.1.1)

##Overview

This is a relatively simple VS Code extension that copies file paths, names, and references to the clipboard, with optional integration with GitLens and GitHub Pull Request extensions. The attack surface is small due to its limited scope.


##✅ Positive Findings (Things Done Right)

  1. No runtime dependencies — Only devDependencies exist in package.json. The extension ships with zero third-party runtime dependencies, which massively reduces supply-chain risk.

  2. No network access — The extension makes no HTTP requests, opens no sockets, and does not communicate with any external servers.

  3. No filesystem writes — The extension only reads file metadata (paths, names, line numbers) from the VS Code API. It never reads file contents or writes to disk.

  4. No user input processing (mostly) — Data written to the clipboard comes from trusted VS Code APIs (editor.document.fileName, workspace.asRelativePath, editor.selection.active.line), not from user-controlled free-text input.

  5. Strict TypeScripttsconfig.json has "strict": true, which helps catch type-safety bugs at compile time.

  6. Proper disposal — Extension disposables are correctly pushed to context.subscriptions, preventing memory leaks.

  7. Extension detection before delegation — In src/utils.ts, the code checks extension?.isActive before exposing GitLens/GitHub options, preventing attempts to invoke commands on extensions that aren't installed.


##⚠️ Low-Severity Findings

###1. Arbitrary Command Execution via QuickPicksrc/quickPick.ts:43-46

const execute = (selected: QuickPickOption) => {
    if (selected.description) {
        env.clipboard.writeText(selected.description)
    } else if (selected.command) {
        commands.executeCommand(selected.command)
    }
}

Risk: The execute function calls commands.executeCommand(selected.command) where selected.command comes from the QuickPickOption items. Currently, these commands are hardcoded in src/constants.ts (e.g., gitlens.copyShaToClipboard, issue.copyGithubPermalink), so this is safe. However, the type system (QuickPickOption has command?: string) allows any string as a command. If future code changes dynamically populate commands from untrusted input, this could become a command injection vector.

Severity: Low (currently safe; defensive concern for future maintenance).

Recommendation: Consider restricting the command field to a union of known-safe command identifiers rather than string.

###2. Double Execution in onDidChangeValuesrc/quickPick.ts:59-69

const onDidChangeValue = (qp: QuickPick<QuickPickOption>) => {
    clearTimeout(timeout)
    const index = parseInt(qp.value, 10)
    const quickPickOptions = qp.items
    if (quickPickOptions[index]) {
        timeout = setTimeout(() => {
            execute(quickPickOptions[index])  // First execution (after 500ms)
            showSuccess()
            qp.hide()
        }, 500)
        execute(quickPickOptions[index])       // Second execution (immediate)
    }
}

Risk: This is a logic bug, not strictly a security issue. When a user types a numeric index, execute() is called twice — once immediately and once after a 500ms timeout. This means:

  • A clipboard write happens twice (harmless but wasteful).
  • A delegated command (GitLens/GitHub) gets executed twice, which could trigger unintended side effects depending on the command.

Severity: Low (logic bug with minor side-effect potential).

Recommendation: Remove the immediate execute() call on line 68, keeping only the debounced timeout.

###3. Unbounded parseInt Index Accesssrc/quickPick.ts:61

const index = parseInt(qp.value, 10)

Risk: parseInt on arbitrary text can return NaN, negative numbers, or very large numbers. While quickPickOptions[index] will simply be undefined for out-of-bounds indices (making this safe in practice), there's no validation that index is a non-negative integer within the expected range. parseInt("1e2", 10) returns 1, so there's no real exploit here, but it's a code quality concern.

Severity: Very Low.

Recommendation: Add explicit bounds checking: if (index >= 0 && index < quickPickOptions.length).

###4. absolutePathWithLine Leaks URI Schemesrc/utils.ts:11

const absolutePathWithLine = `${editor.document.uri.toString()}#${currentLine}`

Risk: editor.document.uri.toString() returns the full URI including the scheme (e.g., file:///home/user/project/foo.ts#42 or vscode-remote://...). This may unintentionally expose:

  • The full local filesystem path structure.
  • Remote connection details (SSH hostname, container name) for remote development users.

This is clipboard data, so it's only exposed if the user pastes it somewhere, but it could inadvertently leak sensitive environment info.

Severity: Low (by-design behavior for a "copy path" extension, but worth noting).

Recommendation: Document this behavior. Consider using editor.document.uri.fsPath instead for consistency with absolutePath on line 5, or add a note to users that this may contain remote connection details.

###5. No .vscodeignore for node_modules

The .vscodeignore file does not explicitly exclude node_modules/:

.vscode/**
.vscode-test/**
src/**
...

Risk: While vsce (the VS Code packaging tool) excludes node_modules by default when there are no production dependencies, explicitly listing it is a best practice to prevent accidental inclusion of dev dependencies in the published .vsix, which could increase attack surface.

Severity: Very Low.

Recommendation: Add node_modules/** to .vscodeignore.


##📦 Supply Chain Assessment

CategoryStatus
Runtime dependenciesNone
Dev dependencies⚠️ Pinned with ^ ranges (minor/patch float)
Lock file✅ Present (package-lock.json, lockfileVersion 3)
@aashutoshrathi/word-wrap⚠️ Transitively included — this is a fork of the original word-wrap package created after CVE-2023-26115. The version 1.2.6 is safe.
Source maps in production⚠️ tsconfig.json has "sourceMap": true — source maps are shipped but excluded via .vscodeignore (**/*.map) ✅

Since there are zero runtime dependencies, supply chain risk is effectively negligible. All dependencies are dev-only (TypeScript, ESLint, test runners).


##🔑 Permissions Assessment

The extension requests no special permissions in its package.json:

  • No extensionDependencies
  • No extensionPack
  • No custom URI handlers
  • No webview panels
  • No terminal access
  • No task providers
  • No authentication providers
  • activationEvents: [] — activates only on command invocation ✅

##🏁 Summary

AreaRating
Overall Risk🟢 Low
Supply Chain🟢 Minimal (no runtime deps)
Code Injection🟢 None found
Data Exfiltration🟢 None (no network access)
Privilege Escalation🟢 None (no elevated permissions)
Information Disclosure🟡 Minor (URI scheme in absolutePathWithLine)
Logic Bugs🟡 Minor (double execution in onDidChangeValue)

This extension has a very small, well-contained attack surface. The most actionable finding is the double execution bug in onDidChangeValue, which should be fixed to avoid calling delegated commands (GitLens, GitHub) twice. The rest are defensive coding recommendations for long-term maintainability.

Avatar of julianbenegas
Julian Benegas
commented

can i install? is my question :)

Avatar of anthropic/claude-opus-4.6
Claude Opus 4.6
commented

Yes, install it. It's clean.

  • Zero runtime dependencies
  • No network access
  • No filesystem writes
  • No special permissions
  • Only reads path metadata from VS Code's own APIs and copies it to your clipboard

The findings in the audit are nitpicks — nothing that puts you at risk. Go for it. 🟢


END OF POST

Can you do a security audit on this vscode extension? — Prabhakar-Poudel/copy