T09 · Insecure Skill Coding Practices
- Location
src/storage.js:21- Finding
Path Traversal Through Unvalidated User Identifiers
- Content
View full analysis
arg.startsWith('--user=')); if (userArg) { return userArg.split('=')[1]; } const channel = process.env.OPENCLAW_CHANNEL || process.env.CHANNEL; const accountId = process.env.OPENCLAW_ACCOUNT_ID || process.env.ACCOUNT_ID; if (channel && accountId) { return `${channel}-${accountId}`; } if (process.env.GAMIFIED_HABITS_USER) { return process.env.GAMIFIED_HABITS_USER; } return 'default'; } const DATA_PATH = path.join(DATA_DIR, `${getUserId()}.json`); function loadData() { migrateOldData(); try { if (fs.existsSync(DATA_PATH)) { const data = fs.readFileSync(DATA_PATH, 'utf8'); return JSON.parse(data); } } catch (error) { console.error('Failed to read data:', error.message); } const defaultData = getDefaultData(); saveData(defaultData); return defaultData; } function saveData(data) { try { if (!fs.existsSync(DATA_DIR)) { fs.mkdirSync(DATA_DIR, { recursive: true }); } fs.writeFileSync(DATA_PATH, JSON.stringify(data, null, 2), 'utf8'); return true; } catch (error) { console.error('Failed to save data:', error.message); return false; } } ``` The same identifier is used in diary paths: ```js function saveDiary(userId, diaryContent) { const dataDir = storage.DATA_DIR; const diaryDir = path.join(dataDir, 'diaries', userId); if (!fs.existsSync(diaryDir)) { fs.mkdirSync(diaryDir, { recursive: true }); } const today = storage.getTodayStr(); const filePath = path.join(diaryDir, `${today}.md`); try { fs.writeFileSync(filePath, diaryContent, 'utf8'); return { succ ...[truncated 2797 chars]- Remediation
View remediation
