T09 · Insecure Skill Coding Practices
Warning
- Location
- index.js:5
- Finding
- State File Path Escapes the Skill Directory## Vulnerability Details **File Location**: `index.js`, lines 5-8 and 31-33 **Vulnerability Type**: Filesystem boundary violation caused by an incorrect state directory **Risk Level**: Medium ### Vulnerable Code ```js const SKILL_DIR = path.join(__dirname, '..', 'claw-todolist'); const STATE_FILE = path.join(SKILL_DIR, 'task_state.json'); const RULES_FILE = path.join(SKILL_DIR, 'todo-rules-v3.2.md'); const DISPLAY_CONFIG_FILE = path.join(SKILL_DIR, 'display_config.json'); ``` ```js function saveState(state) { fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2)); } ``` ### Technical Analysis `__dirname` already identifies the directory containing `index.js`. The expression `path.join(__dirname, '..', 'claw-todolist')` first moves to the parent directory and then selects a sibling directory named `claw-todolist`. As a result, the application reads and writes state using: ```text <parent-of-current-skill>/claw-todolist/task_state.json ``` rather than: ```text <current-skill>/task_state.json ``` This behavior contradicts the persistence boundary declared in `SKILL.md`, which states that persistence is confined to the Skill directory. The path is fixed rather than directly user-controlled, so the evidence does not establish an arbitrary-file-write vulnerability. Nevertheless, it permits the Skill to modify a file outside its own installation directory when a matching sibling directory exists. The same incorrect base directory is used for the rules and display configuration files. This can cause the application to consume configuration from a different installation or to silently use fallback values when the sibling files do not exist. ### Attack Path 1. The Skill is installed in a directory whose name or location differs from the hardcoded sibling path. 2. A directory named `claw-todolist` exists under the current Skill directory's parent, potentially belonging to another installatio ...[truncated 1422 chars]
- Remediation
- ## Remediation Suggestions 1. Use the actual module directory as the Skill directory: ```js const SKILL_DIR = __dirname; const STATE_FILE = path.join(SKILL_DIR, 'task_state.json'); const RULES_FILE = path.join(SKILL_DIR, 'todo-rules-v3.2.md'); const DISPLAY_CONFIG_FILE = path.join(SKILL_DIR, 'display_config.json'); ``` 2. Before filesystem access, resolve and verify that every path remains beneath the approved base directory: ```js const SKILL_DIR = path.resolve(__dirname); function resolveWithinSkill(fileName) { const resolved = path.resolve(SKILL_DIR, fileName); if ( resolved !== SKILL_DIR && !resolved.startsWith(SKILL_DIR + path.sep) ) { throw new Error('Resolved path escapes the Skill directory'); } return resolved; } const STATE_FILE = resolveWithinSkill('task_state.json'); ``` 3. If installed package directories are intended to be read-only, store mutable state in an explicitly approved per-user application data directory rather than beside the source code. Keep rules and display configuration read-only inside the package. 4. Use atomic state updates by writing to a securely created temporary file in the same approved directory and then renaming it over the state file. This reduces corruption from interrupted writes. 5. Add tests that install or execute the Skill under arbitrary directory names and assert that all read and write targets remain within the configured storage boundary. 6. Fail closed when path validation fails, and log the resolved destination without exposing task contents.
