T09 · Insecure Skill Coding Practices
- Location
scripts/lib/utils.js:25- Finding
Path Traversal Through Unvalidated Account Names
- Content
View full analysis
getUsername(a).toLowerCase() === cleanUsername.toLowerCase() ); if (exists) { console.log(`⚠️ @${cleanUsername} 已在监控列表中`); return; } config.accounts.push({ username: cleanUsername, enabled: true, addedAt: new Date().toISOString() }); ``` ```javascript // scripts/lib/utils.js:25-38 async function loadState(username) { const stateFile = path.join(STATE_DIR, `${username}.json`); try { const data = await fs.readFile(stateFile, 'utf8'); return JSON.parse(data); } catch { return { tweets: [], lastCheck: null }; } } async function saveState(username, state) { await fs.mkdir(STATE_DIR, { recursive: true }); const stateFile = path.join(STATE_DIR, `${username}.json`); await fs.writeFile(stateFile, JSON.stringify(state, null, 2)); } ``` ### Technical Analysis The account-management command removes a leading `@` and surrounding whitespace but does not verify that the resulting value conforms to the permitted X.com username syntax. Directory separators and traversal components such as `../` therefore remain accepted. The unvalidated account name is persisted in the configuration and later passed directly to `path.join()` when constructing a state filename. `path.join()` normalizes traversal components; it does not ensure that the final path remains inside `STATE_DIR`. Consequently, a value such as `../../target` can resolve outside `~/.openclaw/x-monitor/state/`. The flaw affects both `loadState()` and `saveState()`. The read operation a ...[truncated 2153 chars]- Remediation
View remediation
