T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/postinstall.js:27- Finding
Destructive Replacement of an Existing Claude Skill Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/postinstall.js:27-41
Vulnerability Type: Destructive installation behavior and unauthorized replacement of user-controlled files
Risk Level: HighVulnerable Code
js if (existsSync(SKILL_LINK)) { try { const stats = lstatSync(SKILL_LINK); if (stats.isSymbolicLink()) { const currentTarget = readlinkSync(SKILL_LINK); if (currentTarget === PACKAGE_ROOT) { console.log('[ttc] Claude Code skill already configured.'); return true; } unlinkSync(SKILL_LINK); } else { rmSync(SKILL_LINK, { recursive: true }); } } catch (err) { console.log(`[ttc] Warning: ${err.message}`); } } symlinkSync(PACKAGE_ROOT, SKILL_LINK);The vulnerable function is invoked automatically by the npm lifecycle configuration in
package.json:28:json "postinstall": "node scripts/postinstall.js"Technical Analysis
During package installation, the script unconditionally takes control of the fixed path
~/.claude/skills/ttc. If that path is a symbolic link to another target, the script removes the link. More seriously, if it is an ordinary file or directory,rmSync(SKILL_LINK, { recursive: true })recursively deletes it.The script does not establish that the existing path was created by this package, does not inspect or preserve its contents, and does not request confirmation. Installation of a transit CLI does not require deletion of pre-existing user-controlled data. This violates least-privilege and safe installer design principles.
The subsequent
symlinkSynccall replaces the removed path with a link to the package root, causing this package to supersede any existing Skill registered under the same name.Attack Path
- The user already has a file, directory, or different symbolic link at
~/.claude/skills/ttc. - The user installs
@lucasygu/ttcthrough npm without disabling lifecycle scripts. - npm automatically executes ...[truncated 982 chars]
- The user already has a file, directory, or different symbolic link at
- Remediation
View remediation
Remediation Suggestions
- If
~/.claude/skills/ttcexists and is not the exact symlink previously created by this package, stop installation without modifying it. - Never recursively delete a pre-existing Skill directory during an automatic package lifecycle hook.
- Require an explicit, separately invoked command and clear confirmation before replacing an existing Skill.
- If replacement is requested, atomically rename the old path to a timestamped backup rather than deleting it.
- Record installation ownership in package-specific metadata and only remove resources that can be reliably attributed to this package.
- Consider making Claude Skill registration opt-in rather than executing it automatically during
postinstall. - Use atomic link creation and report name conflicts with actionable manual instructions.
- If
