T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/admin.js:8
- Finding
- Undisclosed WhatsApp Credential-Store Reconnaissance<![CDATA[ ## Vulnerability Details **File Location**: `scripts/admin.js:8-11, 39-56, 110-143` **Vulnerability Type**: Unauthorized access to sensitive local account metadata **Risk Level**: Medium ### Vulnerable Code ```js const CREDS_PATH = path.join( process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), '.openclaw'), 'credentials', 'whatsapp', 'default' ); ``` ```js const files = fs.readdirSync(CREDS_PATH); const memberFiles = files.filter(f => f.startsWith('sender-key-') && f.includes(groupId)); const members = new Set(); for (const file of memberFiles) { const match = file.match(/--(\\d+)_/); if (match) members.add(match[1]); } let name = null; try { const contactsPath = path.join(CREDS_PATH, 'contacts.json'); if (fs.existsSync(contactsPath)) { const contacts = JSON.parse(fs.readFileSync(contactsPath, 'utf8')); if (contacts[groupId]) { name = contacts[groupId].name || contacts[groupId].subject; } } } catch (e) { /* contacts not available */ } ``` ```js const files = fs.readdirSync(CREDS_PATH); const groupData = new Map(); for (const file of files) { if (file.startsWith('sender-key-') && file.includes('@g.us')) { const match = file.match(/sender-key-(.+@g\.us)--(\d+)/); if (match) { const groupId = match[1]; const memberId = match[2]; if (!groupData.has(groupId)) { groupData.set(groupId, { id: groupId, members: new Set() }); } groupData.get(groupId).members.add(memberId); } } } // Enrich with names try { const contactsPath = path.join(CREDS_PATH, 'contacts.json'); if (fs.existsSync(contactsPath)) { const contacts = JSON.parse(fs.readFileSync(contactsPath, 'utf8')); for (const [id, data] of groupData) { if (contacts[id]) { data.name = contacts[id].name || contacts[id].subject; } } } } catch (e) { /* contacts not available */ } ``` ### Technical Analysis The `info` and `list` commands directly enumerate OpenClaw's default W ...[truncated 2358 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace credential-directory scanning with an authenticated WhatsApp API that enforces the account's access controls. 2. Require explicit user confirmation before accessing locally stored WhatsApp state or displaying group metadata. 3. Clearly document all credential-store access in `SKILL.md`, including the exact data read and emitted. 4. Apply least privilege by avoiding participant-level identifier extraction when only aggregate statistics are required. 5. Redact group and participant identifiers by default, exposing full values only through an explicitly authorized option. 6. Validate and canonicalize `OPENCLAW_STATE_DIR`, then restrict access to an approved state root to prevent unintended directory selection. 7. Add an authorization boundary so that merely being able to invoke the skill does not automatically permit credential-state inspection. 8. Record security-relevant access without logging the sensitive metadata itself. 9. Return a clear error when authorization or consent is absent rather than silently inspecting the credential directory. ]]>
