T09 · Insecure Skill Coding Practices
- Location
scripts/heartbeat.js:88- Finding
Unrestricted Shell Command Execution from Workspace Configuration
- Content
View full analysis
{ const start = Date.now(); try { const output = execSync(check.command, { encoding: 'utf8', timeout: timeoutMs, stdio: ['ignore', 'pipe', 'pipe'], shell: true, env: { ...process.env }, }).trim(); resolve({ ...check, ok: true, output, ms: Date.now() - start }); ``` ### Technical Analysis The `command` property is read from the workspace-controlled `heartbeat.yaml` configuration and passed directly to `execSync` with `shell: true`. No command allowlist, executable validation, configuration ownership check, or argument separation is applied. Because a shell interprets the entire value, the configuration can contain pipelines, substitutions, redirections, command separators, and arbitrary additional commands. The child process also receives a copy of the complete parent environment through `env: { ...process.env }`. Any API keys, tokens, credentials, or sensitive configuration stored in environment variables are therefore accessible to the configured command. Although command execution is part of the Skill's documented purpose, the configuration is effectively executable code. Treating an untrusted or insufficiently protected workspace configuration as ordinary data creates a command-injection boundary. The scheduled execution workflow documented in `SKILL.md:58-64` increases the exposure because a malicious configuration may execute repeatedly without interactive review. ### Attack Path 1. An attacker, compromised tool, malicious repository contribution, or other untrusted process gains the ability to create or modify `heartbeat.yaml`. 2. The attacker inserts a shell payload into a collector ...[truncated 1013 chars]- Remediation
View remediation
