Back to skill

Security audit

Gmail Cleaner

Security checks for vulnerabilities and agentic risk

Overview

This Gmail cleanup skill does what it says, but it asks for powerful mailbox access and includes unsafe defaults and implementation choices that could cause data loss or local code execution if misused.

Review before installing. Use only with Gmail accounts where you are comfortable granting modify/delete and settings access. Run scan and dry-run modes first, avoid deep_clean.py without --skip-trash-purge unless you intentionally want old trash permanently deleted, never use token.pkl files from another person, protect or revoke OAuth tokens when finished, and prefer installing pinned dependencies manually in an isolated environment.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/auth.py:58
Finding

Unsafe Deserialization of Attacker-Controlled OAuth Token Files

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.py:58-60, scripts/clean.py:49-51, scripts/deep_clean.py:39-41, scripts/organize.py:95-97, scripts/restore.py:53-55, and scripts/scan.py:29-31
Vulnerability Type: Unsafe Python pickle deserialization
Risk Level: High

Vulnerable Code

The following pattern appears in every Gmail utility:

python
with open(args.token, 'rb') as f:
    creds = pickle.load(f)

The token path is supplied through a command-line argument. For example, scripts/clean.py defines it as follows:

python
parser.add_argument('--token', default=DEFAULT_TOKEN)

with open(args.token, 'rb') as f:
    creds = pickle.load(f)
if creds.expired and creds.refresh_token:
    creds.refresh(Request())
    with open(args.token, 'wb') as f:
        pickle.dump(creds, f)

Technical Analysis

Python pickle is an executable serialization format. During pickle.load(), objects may define reduction operations that invoke arbitrary Python callables. Consequently, loading a pickle does not merely parse data: a malicious pickle can execute operating-system commands before the returned object is used.

Each affected script accepts an arbitrary token-file path through --token and passes that file directly to pickle.load() without verifying its origin, ownership, permissions, type, or integrity. An attacker who can provide a token file, replace the default token, influence a wrapper command, or write to the token directory can therefore obtain code execution when the victim runs any affected utility.

The issue is present at these locations:

  • scripts/auth.py:58-60
  • scripts/clean.py:49-51
  • scripts/deep_clean.py:39-41
  • scripts/organize.py:95-97
  • scripts/restore.py:53-55
  • scripts/scan.py:29-31

Attack Path

  1. An attacker creates a malicious pickle whose reduction payload invokes a command, Python function, or executable.
  2. The att ...[truncated 1582 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace pickle token storage with a non-executable format. Use Google credential JSON serialization or another strictly data-only representation.
  2. Parse only an explicit allowlist of credential fields and reject unknown or incorrectly typed values.
  3. Migrate existing trusted pickle tokens once, then delete the legacy pickle files. Do not automatically deserialize arbitrary legacy files during normal operation.
  4. Store token files in a fixed, application-controlled directory rather than accepting arbitrary paths by default.
  5. Enforce restrictive permissions:
    • create directories with mode 0700;
    • create token files with mode 0600;
    • reject token files owned by another user;
    • reject symbolic links and non-regular files.
  6. Use atomic writes with a securely created temporary file in the same protected directory.
  7. If legacy pickle loading is temporarily unavoidable, clearly require an explicit migration command and only accept an owner-controlled regular file from the protected token directory. This reduces exposure but does not make unpickling intrinsically safe.
  8. Revoke and regenerate tokens if an existing pickle file may have come from an untrusted source.

T08 · Insecure Dependencies

Warning
Location
scripts/auth.py:45
Finding

Automatic Installation and Execution of Unpinned Runtime Dependencies

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.py:45-52, scripts/clean.py:41-48, scripts/deep_clean.py:31-38, scripts/organize.py:87-94, scripts/restore.py:45-52, and scripts/scan.py:21-28
Vulnerability Type: Unpinned runtime dependency installation
Risk Level: Medium

Vulnerable Code

scripts/auth.py automatically installs mutable package versions when imports fail:

python
try:
    from google_auth_oauthlib.flow import InstalledAppFlow
    from google.auth.transport.requests import Request
except ImportError:
    print("Installing required packages...")
    os.system(f"{sys.executable} -m pip install google-auth-oauthlib google-auth-httplib2 google-api-python-client -q")
    from google_auth_oauthlib.flow import InstalledAppFlow
    from google.auth.transport.requests import Request

The remaining scripts use the same pattern. For example, scripts/clean.py contains:

python
try:
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

Equivalent installation logic is present in:

  • scripts/deep_clean.py:31-38
  • scripts/organize.py:87-94
  • scripts/restore.py:45-52
  • scripts/scan.py:21-28

Technical Analysis

The scripts combine application execution with dependency installation. Package names are not constrained to exact versions and no cryptographic hashes are supplied. As a result, the artifacts installed during one run may differ from those reviewed or installed during another run.

Package installation and subsequent imports execute third-party code under the user's account. Security therefore depends on the current state of the configured Python package index, network path, ...[truncated 1967 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove all automatic pip install calls from runtime scripts.
  2. Declare dependencies in a dedicated lock file with exact versions.
  3. Generate and enforce cryptographic hashes for every direct and transitive dependency, such as with a hash-locked requirements file and pip install --require-hashes.
  4. Install dependencies during a separate, explicit setup phase in an isolated virtual environment.
  5. When dependencies are unavailable, terminate with a clear error and provide installation instructions instead of modifying the environment automatically.
  6. Use a trusted, explicitly configured package index and secure transport.
  7. Regularly scan locked packages for known vulnerabilities and update them through a reviewed dependency-management process.
  8. Prefer reproducible builds or signed, prebuilt environments for deployments that handle OAuth credentials.
  9. Avoid broad exception-based installation behavior. An ImportError can originate from a broken transitive import rather than a genuinely absent package; report the original error instead of attempting an uncontrolled reinstall.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (42)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

If the referenced code chunk primarily scans/report mailbox data rather than cleaning, the manifest still overstates the skill's operational behavior. Even when not directly exploitable as code execution, this kind of capability inflation can cause unsafe delegation decisions and overbroad trust in a mailbox-management skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the referenced code chunk primarily scans/report mailbox data rather than cleaning, the manifest still overstates the skill's operational behavior. Even when not directly exploitable as code execution, this kind of capability inflation can cause unsafe delegation decisions and overbroad trust in a mailbox-management skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the referenced code chunk primarily scans/report mailbox data rather than cleaning, the manifest still overstates the skill's operational behavior. Even when not directly exploitable as code execution, this kind of capability inflation can cause unsafe delegation decisions and overbroad trust in a mailbox-management skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the referenced code chunk primarily scans/report mailbox data rather than cleaning, the manifest still overstates the skill's operational behavior. Even when not directly exploitable as code execution, this kind of capability inflation can cause unsafe delegation decisions and overbroad trust in a mailbox-management skill.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
80% confidence
Finding

The skill instructs handling OAuth credentials and token pickle files from local paths, which are sensitive secrets that can grant mailbox access. Exposing, mishandling, or over-broadly reading these files could lead to account compromise across one or more Gmail accounts.

Content

Scanner excerpt · SKILL.md (reported line 21)May include surrounding context.

1. Auth (first time or new account)

bash
python scripts/auth.py --credentials /path/to/credentials.json --token /path/to/token.pkl --scopes settings
  • basic scopes: read/modify/delete messages + labels

Credential Access

High
Category
Privilege Escalation
Confidence
85% confidence
Finding

Storing default credential and token files in predictable workspace locations increases the chance of accidental disclosure or misuse by other tools, users, or processes with filesystem access. Because these artifacts enable Gmail API access, compromise can result in reading, modifying, deleting, or reconfiguring mailbox data.

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

md
- `basic` scopes: read/modify/delete messages + labels  
- `settings` scopes: adds `gmail.settings.basic` (required for creating filters)  
- Default token path: `~/.openclaw/workspace/gmail_token.pkl`
- Default creds path: `~/.openclaw/workspace/gmail_credentials.json`

For a second account, specify a different `--token` path (e.g., `gmail_token_work.pkl`).

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 46)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 49)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 55)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 110)May include surrounding context.

md
python scripts/clean.py --from "spam@example.com,news@example.org"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/auth.py (reported line 36)May include surrounding context.

python
],
}

DEFAULT_CREDS = os.path.join(os.path.expanduser('~'), '.openclaw', 'workspace', 'gmail_credentials.json')
DEFAULT_TOKEN = os.path.join(os.path.expanduser('~'), '.openclaw', 'workspace', 'gmail_token.pkl')

parser = argparse.ArgumentParser(description='Gmail OAuth authentication')

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The script executes a shell command to install packages at runtime using os.system, which is unnecessary for core authentication logic and introduces command-execution and supply-chain risk. Even though the interpolated executable path comes from sys.executable, this still runs external code from the network during authentication and can be abused in compromised environments or when package sources are malicious or poisoned.

Content

Scanner excerpt · scripts/auth.py (reported line 50)May include surrounding context.

python
from google.auth.transport.requests import Request
except ImportError:
    print("Installing required packages...")
    os.system(f"{sys.executable} -m pip install google-auth-oauthlib google-auth-httplib2 google-api-python-client -q")
    from google_auth_oauthlib.flow import InstalledAppFlow
    from google.auth.transport.requests import Request

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
91% confidence
Finding

The script automatically invokes os.system() to run pip install when imports fail, causing shell execution and unreviewed dependency installation at runtime. Although sys.executable is usually trusted, this still executes external commands without confirmation and expands the attack surface through dependency confusion, malicious package mirrors, or manipulated environment/package indexes.

Content

Scanner excerpt · scripts/clean.py (reported line 46)May include surrounding context.

python
from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
91% confidence
Finding

The script invokes os.system() to install packages at runtime, which executes a shell command and introduces unnecessary command execution capability into a Gmail-cleaning utility. While sys.executable is usually trusted, this still expands the attack surface, depends on external package indexes at execution time, and can be abused in compromised environments or through dependency-chain attacks.

Content

Scanner excerpt · scripts/deep_clean.py (reported line 36)May include surrounding context.

python
from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script permanently deletes messages from Gmail trash without interactive confirmation, despite the action being irreversible and enabled by default unless --skip-trash-purge is passed. In a bulk-cleaning tool with broad mailbox access, this greatly increases the chance of destructive data loss from user error, bad query assumptions, or misuse.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
94% confidence
Finding

The script invokes os.system() to run a pip install command at runtime, which introduces shell execution and unauthorized environment modification beyond the stated Gmail organization purpose. Even though sys.executable is usually trusted, shell-based package installation creates supply-chain and execution risk, and in an agent setting can fetch and run external code unexpectedly.

Content

Scanner excerpt · scripts/organize.py (reported line 92)May include surrounding context.

python
from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

On ImportError, the script invokes os.system() to run pip at runtime. Although sys.executable is not directly attacker-controlled here, executing shell commands from the script expands the attack surface, can install unpinned packages unexpectedly, and may execute in compromised environments without user awareness.

Content

Scanner excerpt · scripts/restore.py (reported line 50)May include surrounding context.

python
from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
89% confidence
Finding

The script invokes os.system() to install packages at runtime, giving a mailbox scanning utility unnecessary shell execution capability. While sys.executable is usually trusted, runtime package installation expands the attack surface through shell invocation, dependency confusion/supply-chain risk, and execution of package install hooks.

Content

Scanner excerpt · scripts/scan.py (reported line 26)May include surrounding context.

python
from google.auth.transport.requests import Request
    from googleapiclient.discovery import build
except ImportError:
    os.system(f"{sys.executable} -m pip install google-api-python-client google-auth -q")
    from google.auth.transport.requests import Request
    from googleapiclient.discovery import build

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises and instructs use of shell commands, local credential/token files, and Gmail API access, but declares no explicit tool scope or permissions boundaries. That makes its effective capabilities broader and less auditable, increasing the chance of unintended file access, command execution, or network use when the skill is invoked.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The skill explicitly supports OAuth token files for one or multiple Gmail accounts, which introduces session persistence beyond a single invocation. Persistent tokens increase the blast radius of compromise because a stolen or reused token can allow continued mailbox access without re-authentication.

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.

md
---
name: gmail-cleaner
description: Clean and organize Gmail accounts in bulk. Use when asked to clean Gmail, remove spam, trash newsletters/promotional emails, bulk-delete emails by sender, create labels, set up auto-filters, or restore emails from trash. Handles single or multiple Gmail accounts via OAuth token files. Works with any Gmail account using the Gmail API.
---

# Gmail Cleaner

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The activation text is very broad ('clean Gmail', 'remove spam', 'restore emails', etc.), making it likely to trigger on ordinary user requests without sufficient intent verification. In a skill that can delete or modify mailbox contents, accidental activation materially raises the risk of unauthorized or unintended destructive actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

On import failure, the script informs the user that it is installing packages and then executes a pip install command through the shell. Although there is a print statement immediately before execution, the module docstring and usage text do not disclose that running this helper may invoke subprocess/package installation on the user's system.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This authentication helper has the capability to fetch and install Python packages at runtime, which expands its behavior beyond Gmail OAuth and adds avoidable supply-chain exposure. In the context of a Gmail-cleaning skill that handles sensitive mail access tokens, silently changing the local Python environment is more dangerous because it can introduce unreviewed code into a high-trust workflow.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.