fix: don't embed shell-unsafe install paths in statusline setup nudge (#224)
The SessionStart nudge built a statusLine command by interpolating the plugin's __dirname path into a double-quoted shell string. A clone path containing shell metacharacters (quotes, &, $, backtick, ;) could break out when the suggested command later runs via the statusline shell. Low severity in practice: the path is the install location, so triggering it requires installing into a maliciously-named directory, i.e. the attacker already controls the filesystem. Hardening it anyway. Gate the snippet behind isShellSafe() (allowlist of ordinary path chars, allowing : \ / for normal Windows and POSIX paths). Unsafe paths fall back to a manual-setup instruction instead of an embeddable command. An allowlist beats a per-shell escaper, which is its own edge-case bug farm. Refs #200
This commit is contained in:
@@ -8,6 +8,16 @@ const { spawnSync } = require('child_process');
|
||||
|
||||
const root = path.join(__dirname, '..');
|
||||
|
||||
// isShellSafe gates the statusline setup snippet (issue #200): ordinary install
|
||||
// paths pass, paths carrying shell metacharacters are rejected so they never get
|
||||
// embedded in a shell command.
|
||||
const { isShellSafe } = require('../hooks/ponytail-config');
|
||||
assert.equal(isShellSafe('C:\\Users\\x\\.claude\\plugins\\ponytail\\hooks\\ponytail-statusline.ps1'), true);
|
||||
assert.equal(isShellSafe('/home/u/.claude/plugins/ponytail/hooks/ponytail-statusline.sh'), true);
|
||||
assert.equal(isShellSafe('/tmp/a"&calc.exe&"/x.sh'), false);
|
||||
assert.equal(isShellSafe('/tmp/$(calc)/x.sh'), false);
|
||||
assert.equal(isShellSafe('/tmp/a;rm -rf/x.sh'), false);
|
||||
|
||||
function run(script, env, input = '') {
|
||||
return spawnSync(process.execPath, [path.join(root, 'hooks', script)], {
|
||||
env: { ...process.env, ...env },
|
||||
|
||||
Reference in New Issue
Block a user