T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/groupManager.js:17
- Finding
- Unrestricted Caller-Controlled Filesystem Access## Vulnerability Details **File Location**: `scripts/groupManager.js`, lines 17–72 **Vulnerability Type**: Arbitrary file read, file overwrite, and directory creation through an unrestricted path **Risk Level**: Medium ### Vulnerable Code ```javascript let GROUPS_FILE = path.join(process.cwd(), 'feishu-groups.json'); /** * 设置群信息文件路径 * @param {string} customPath - 自定义路径 */ function setGroupsFilePath(customPath) { if (customPath) { GROUPS_FILE = customPath; } } /** * 获取当前群信息文件路径 * @returns {string} */ function getGroupsFilePath() { return GROUPS_FILE; } /** * 初始化群信息文件 * @param {string} customPath - 可选的自定义路径 */ function initGroupsFile(customPath) { const filePath = customPath || GROUPS_FILE; if (!fs.existsSync(filePath)) { // 确保目录存在 const dir = path.dirname(filePath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } const initialData = { groups: {}, updated_at: new Date().toISOString() }; fs.writeFileSync(filePath, JSON.stringify(initialData, null, 2)); console.log(`[群管理] 初始化群信息文件: ${filePath}`); } return JSON.parse(fs.readFileSync(filePath, 'utf8')); } /** * 读取群信息 * @param {string} customPath - 可选的自定义路径 */ function getGroups(customPath) { const filePath = customPath || GROUPS_FILE; initGroupsFile(filePath); return JSON.parse(fs.readFileSync(filePath, 'utf8')); } /** * 保存群信息 * @param {object} data - 群信息数据 * @param {string} customPath - 可选的自定义路径 */ function saveGroups(data, customPath) { const filePath = customPath || GROUPS_FILE; data.updated_at = new Date().toISOString(); fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); } ``` ### Technical Analysis The module accepts an unrestricted `customPath` and also exposes `setGroupsFilePath()`, which permanently changes the module-level storage target. The supplied path is not normaliz ...[truncated 2762 chars]
- Remediation
- ## Remediation Suggestions 1. Remove public `customPath` parameters from ordinary group-management functions unless they are strictly required. 2. Establish one trusted storage root, such as the current agent's workspace, and resolve every requested path relative to that root. 3. Canonicalize and validate the target before access: ```javascript const STORAGE_ROOT = path.resolve(process.env.AGENT_WORKSPACE); const DEFAULT_FILE = path.join(STORAGE_ROOT, 'feishu-groups.json'); function validateGroupsPath(candidate = DEFAULT_FILE) { const resolved = path.resolve(candidate); const relative = path.relative(STORAGE_ROOT, resolved); if (relative.startsWith('..') || path.isAbsolute(relative)) { throw new Error('Groups file must remain inside the agent workspace'); } return resolved; } ``` 4. Reject symbolic links and non-regular files. Validate existing path components with `fs.lstatSync()` and compare canonical paths using `fs.realpathSync()` before reading or replacing a target. 5. Create the storage directory and file with restrictive permissions, such as directory mode `0700` and file mode `0600`. 6. Use atomic writes: write to a securely created temporary file in the same validated directory, flush it, and rename it over the destination. 7. Validate the loaded JSON schema before using or modifying it. Require `groups` to be a plain object and validate each stored field. 8. Avoid returning raw contents from arbitrary storage targets and sanitize filesystem errors before exposing them to untrusted callers. 9. Add tests covering absolute paths, `../` traversal, symbolic links, missing parent directories, malformed JSON, and attempts to target files outside the workspace.
