mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-23 16:41:22 +08:00
fix(security): contain install-state file ops to trusted root — RCE fix (GHSA-hfpv-w6mp-5g95)
Critical: project-local install-state (e.g. a cloned repo's .cursor/ecc-install-state.json) is attacker-controllable, and repair/uninstall/auto-update replayed its operations with destinationPath validated only for non-emptiness — confirmed arbitrary file write/delete and chained RCE (write ~/.bashrc, .git/hooks, or run a planted install-apply.js). - New scripts/lib/path-safety.js: assertWithinTrustedRoot() canonicalizes (incl. symlink escape via nearest-existing-ancestor realpath) and fails closed unless the destination is within the adapter-derived trusted root. - install-lifecycle.js: gate executeRepairOperation + executeUninstallOperation + the install-state removal against record.targetRoot (the adapter-resolved root, NOT the attacker-supplied state.target.root). - auto-update.js: validateRepoRoot now requires package.json name to be an official ECC package, so a planted nested repo can't drive auto-update into executing attacker code. - 7 containment regression tests. Existing install-lifecycle/repair/uninstall/auto-update suites still green (legit destinations are within the root).
This commit is contained in:
@@ -123,6 +123,12 @@ function determineInstallCwd(record, repoRoot) {
|
||||
return repoRoot;
|
||||
}
|
||||
|
||||
// Recognized ECC package names. A repo root is only trusted to run its
|
||||
// install-apply.js if its package.json identifies it as ECC — otherwise a
|
||||
// cloned project that ships a nested `evil/{package.json,scripts/install-apply.js}`
|
||||
// could drive auto-update into executing attacker code (GHSA-hfpv-w6mp-5g95).
|
||||
const ECC_PACKAGE_NAMES = new Set(['ecc-universal', 'everything-claude-code']);
|
||||
|
||||
function validateRepoRoot(repoRoot) {
|
||||
const normalized = path.resolve(repoRoot);
|
||||
const packageJsonPath = path.join(normalized, 'package.json');
|
||||
@@ -136,6 +142,18 @@ function validateRepoRoot(repoRoot) {
|
||||
throw new Error(`Invalid ECC repo root: missing install script at ${installApplyPath}`);
|
||||
}
|
||||
|
||||
let pkgName = null;
|
||||
try {
|
||||
pkgName = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).name;
|
||||
} catch {
|
||||
throw new Error(`Invalid ECC repo root: unreadable package.json at ${packageJsonPath}`);
|
||||
}
|
||||
if (!ECC_PACKAGE_NAMES.has(pkgName)) {
|
||||
throw new Error(
|
||||
`Refusing to run install from untrusted repo root ${normalized}: package.json name '${pkgName}' is not an official ECC package.`
|
||||
);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user