Back to skill

Security audit

WhatsApp Validate

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly coherent, but it can expose sensitive WhatsApp contact identifiers from local session/cache data without a clear privacy warning or strong limits.

Install only if you are comfortable letting the skill read your local OpenClaw WhatsApp/Baileys cache and print full phone numbers and JIDs. Avoid using the list command unless you intend to disclose cached contact identifiers into the agent session or logs.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/validate.js:96
Finding

Unrestricted Enumeration of Cached WhatsApp Phone Numbers and JIDs

Content
View full analysis

Vulnerability Details

File Location: scripts/validate.js, lines 6–10, 18–43, and 96–101
Vulnerability Type: Unrestricted access to sensitive local WhatsApp cache data
Risk Level: Medium

The skill reads phone numbers from the OpenClaw WhatsApp/Baileys credential-cache directory. Its list command prints cached phone numbers and corresponding WhatsApp JIDs without authorization checks, user confirmation, output masking, or an enforced maximum result count.

Vulnerable Code

js
const CREDS_PATH = path.join(
  process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), '.openclaw'),
  'credentials', 'whatsapp', 'default'
);
js
function loadKnownNumbers() {
  const numbers = new Set();

  try {
    const files = fs.readdirSync(CREDS_PATH);

    for (const file of files) {
      // session-NUMBER.json
      if (file.startsWith('session-')) {
        const match = file.match(/session-(\d+)_/);
        if (match) numbers.add(match[1]);
      }
      // device-list-NUMBER.json
      if (file.startsWith('device-list-')) {
        const match = file.match(/device-list-(\d+)\.json/);
        if (match) numbers.add(match[1]);
      }
    }

    // Also load from contacts file
    try {
      const contactsPath = path.join(CREDS_PATH, 'contacts.json');
      if (fs.existsSync(contactsPath)) {
        const contacts = JSON.parse(fs.readFileSync(contactsPath, 'utf8'));
        for (const jid of Object.keys(contacts)) {
          if (jid.endsWith('@s.whatsapp.net')) {
            numbers.add(jid.replace('@s.whatsapp.net', ''));
          }
        }
      }
    } catch (e) { /* contacts not available */ }

  } catch (error) {
    console.error(JSON.stringify({ error: error.message }));
    process.exit(1);
  }

  return numbers;
}
js
function listKnown(limit = 50) {
  const numbers = Array.from(loadKnownNumbers()).slice(0, parseInt(limit));

...[truncated 2610 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the bulk list command unless full contact enumeration is an explicit and necessary feature.
  2. Require an explicit authorization check before accessing or displaying cached WhatsApp identifiers.
  3. Restrict the skill to single-number membership checks where possible, returning only a Boolean result rather than a phone number or JID.
  4. Mask sensitive values by default, such as displaying only the final two to four digits.
  5. Do not print reconstructed JIDs unless they are strictly required by an authorized workflow.
  6. Enforce a small, fixed upper bound on list results and reject non-integer, negative, non-finite, or excessive limits.
  7. Prevent sensitive output from being retained in agent transcripts and execution logs, or mark it for mandatory redaction.
  8. Apply least-privilege filesystem permissions to the WhatsApp credential-cache directory and execute the skill only in trusted contexts.
  9. Document that cache output contains personal data and establish appropriate retention, consent, and access-control policies.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is presented as a validator for whether numbers exist in local cache, but its documented behavior includes listing all known numbers and reading an additional contacts data source. That mismatch is dangerous because it hides bulk enumeration and disclosure capabilities behind a benign-sounding description, which could enable unauthorized harvesting of previously seen WhatsApp identifiers from local state.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The list command dumps all known numbers from the local Baileys/WhatsApp cache, enabling bulk extraction of contact identifiers from sensitive local state. In this skill context, the stated purpose is single/batch validation, so mass enumeration is unnecessary and materially more dangerous because it can expose an entire contact graph or prior user interactions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
78% confidence
Finding

The skill invokes a Node.js script and static analysis detected environment/code capabilities, but the manifest does not declare any tool scope or permissions. Missing scope declarations make the skill's effective capabilities opaque to reviewers and agents, increasing the chance that sensitive local data or environment-derived secrets are accessed without appropriate user awareness or policy gating.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill documents a list command that exposes previously seen phone numbers from the local WhatsApp/Baileys cache, but it provides no warning about the privacy implications. In this context, cached phone numbers are sensitive contact data, and omission of a warning increases the likelihood of unintentional disclosure or misuse during routine use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The code reads phone numbers and contact-derived JIDs from local credential/cache files and prints them to CLI output without any privacy notice, minimization, or masking. Even though this is local data access, the information is personally identifying and could be exposed to logs, calling wrappers, or unauthorized users of the environment.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill metadata says it validates whether phone numbers exist in the local cache, but the code also provides a list capability that enumerates cached WhatsApp identifiers. That broadens behavior from targeted validation to bulk disclosure of locally stored contact/session data, increasing privacy and data-exposure risk beyond the declared purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.