Back to skill

Security audit

gmail-connect

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed local Gmail connector with expected OAuth, local storage, optional sending, and optional background polling behavior.

Before installing, understand that this skill stores Gmail OAuth client credentials, tokens, cached mail metadata, and local drafts on your Ubuntu account in owner-only but unencrypted files. Keep the wizard link and Google credential JSON private, leave sending disabled unless you need it, and enable background checks only if you want a persistent user-level Gmail polling service.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is about Gmail connectivity and mail operations, but the supplied code does none of that. It does not authenticate with Gmail, launch an OAuth wizard, search/read messages, check for new mail, or send drafts. Instead, it packages the skill by copying markdown documents and directories such as scripts, assets, references, and tests into a new output folder. This is a materially different primary purpose and introduces undeclared filesystem export behavior unrelated to the stated Gmail functionality.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is about Gmail integration and mail operations, but the actual code chunk does not interact with Gmail, OAuth, Ubuntu integration, email search/reading, message polling, or draft sending. Instead, it is purely a regression test for a packaging script that exports files and enforces filesystem safety constraints. This is a materially different primary purpose, so the description does not accurately represent the code.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

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

md
giving the user its private browser link. Do not expose that link to group chats or public logs. If a private link cannot be delivered safely, have the user launch the same command in their Ubuntu terminal, which opens their browser automatically. Keep it running until setup completes.

If host exec is sandboxed or this skill is on a different machine, do not copy credentials into the sandbox or disable security globally. Have the user run the launcher on their Ubuntu host. Ordinary read operations also need access to that same host and user state.

Guide the user through project creation, Gmail API enablement, OAuth consent, a Desktop client JSON upload, and browser authorization. Never request passwords, refresh tokens, authorization codes, client secrets, gateway secrets, or credential JSON in chat. Google handles account selection. Verify the displayed account matches the user's intended mailbox before using it.

Require Python 3.10+ and an existing OpenClaw installation. If Pytho

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

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

md
Guide the user through project creation, Gmail API enablement, OAuth consent, a Desktop client JSON upload, and browser authorization. Never request passwords, refresh tokens, authorization codes, client secrets, gateway secrets, or credential JSON in chat. Google handles account selection. Verify the displayed account matches the user's intended mailbox before using it.

Require Python 3.10+ and an existing OpenClaw installation. If Python is missing, offer `sudo apt update && sudo apt install python3 ca-certificates` in the user's terminal. Never install or upgrade OpenClaw, replace its configuration, stop its gateway, or alter its models/channels during Gmail setup. The wizard can create or stop only its own `openclaw-gmail-connect.service`, when the user clicks the corresponding control.

## Use Gmail

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/operations.md (reported line 116)May include surrounding context.

bash
systemctl --user disable --now openclaw-gmail-connect.service
rm -f "$HOME/.config/systemd/user/openclaw-gmail-connect.service"
systemctl --user daemon-reload

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill text instructs execution of Python scripts, local file handling, network access to Google APIs, and shell commands, but the manifest does not declare an explicit tool scope such as permissions or allowed-tools. That gap increases the chance the runtime grants broader capabilities than users or reviewers expect, which is risky for a skill that handles OAuth tokens, local drafts, and filesystem state.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
<li><a id="branding-link" target="_blank" rel="noopener noreferrer">Configure Google Auth Platform ↗</a><p>Set the app name and audience, add your account as a test user when External, and declare only the Gmail access you need.</p><details class="guide"><summary>Show Branding, Audience, and Data Access steps</summary><ol><li>Open Google Auth Platform. If it says <b>Not configured yet</b>, click <b>Get started</b>.</li><li>Under <b>App Information</b>, name the app <code>OpenClaw Gmail Connect</code>, choose your support email, and click <b>Next</b>.</li><li>Under <b>Audience</b>, personal Gmail users choose <b>External</b>. <b>Internal</b> is only for an eligible Google Workspace organization. Click <b>Next</b>.</li><li>Under <b>Contact Information</b>, enter your email and click <b>Next</b>.</li><li>Under <b>Finish</b>, review Google’s User Data Policy, select <b>I agree</b> if you accept it, click <b>Continue</b>, then click <b>Create</b>.</li><li>If External and in Testing, open <b>Audience → Test users → Add users</b>, enter the exact Gmail account you will authorize, and save it.</li><li>Open <b>Data Access → Add or Remove Scopes</b>. Select <code>https://www.googleapis.com/auth/gmail.readonly</code>. Select <code>https://www.googleapis.com/auth/gmail.send</code> only if you will enable reviewed sending in Step 2, then click <b>Update</b> or <b>Save</b> as shown.</li></ol><div class="actions"><a id="audience-link" class="button secondary" target="_blank" rel="noopener noreferrer">Open Audience ↗</a><a id="data-link" class="button secondary" target="_blank" rel="noopener noreferrer">Open Data Access ↗</a><a target="_blank" rel="noopener noreferrer" href="https://developers.google.com/workspace/guides/configure-oauth-consent">Google’s consent guide ↗</a></div></details><p class="hint">External apps in Testing can lose Gmail refresh tokens after 7 days. For longer use, review Google’s Production and verification requirements. Workspace policy can still require ad
...[truncated 26 chars]

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · assets/ui/index.html (reported line 12)May include surrounding context.

html
<li><a id="branding-link" target="_blank" rel="noopener noreferrer">Configure Google Auth Platform ↗</a><p>Set the app name and audience, add your account as a test user when External, and declare only the Gmail access you need.</p><details class="guide"><summary>Show Branding, Audience, and Data Access steps</summary><ol><li>Open Google Auth Platform. If it says <b>Not configured yet</b>, click <b>Get started</b>.</li><li>Under <b>App Information</b>, name the app <code>OpenClaw Gmail Connect</code>, choose your support email, and click <b>Next</b>.</li><li>Under <b>Audience</b>, personal Gmail users choose <b>External</b>. <b>Internal</b> is only for an eligible Google Workspace organization. Click <b>Next</b>.</li><li>Under <b>Contact Information</b>, enter your email and click <b>Next</b>.</li><li>Under <b>Finish</b>, review Google’s User Data Policy, select <b>I agree</b> if you accept it, click <b>Continue</b>, then click <b>Create</b>.</li><li>If External and in Testing, open <b>Audience → Test users → Add users</b>, enter the exact Gmail account you will authorize, and save it.</li><li>Open <b>Data Access → Add or Remove Scopes</b>. Select <code>https://www.googleapis.com/auth/gmail.readonly</code>. Select <code>https://www.googleapis.com/auth/gmail.send</code> only if you will enable reviewed sending in Step 2, then click <b>Update</b> or <b>Save</b> as shown.</li></ol><div class="actions"><a id="audience-link" class="button secondary" target="_blank" rel="noopener noreferrer">Open Audience ↗</a><a id="data-link" class="button secondary" target="_blank" rel="noopener noreferrer">Open Data Access ↗</a><a target="_blank" rel="noopener noreferrer" href="https://developers.google.com/workspace/guides/configure-oauth-consent">Google’s consent guide ↗</a></div></details><p class="hint">External apps in Testing can lose Gmail refresh tokens after 7 days. For longer use, review Google’s Production and verification requirements. Workspace policy can still require ad
...[truncated 26 chars]

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/operations.md (reported line 49)May include surrounding context.

md
In the wizard:

1. Open Google Cloud and create or choose your project. Enter its actual project ID.
2. Follow the Gmail API link and enable it in that same project.
3. Complete Google Auth Platform branding, audience and data access. For a personal Gmail account use External. If in Testing, add your account as a test user. Request `gmail.readonly`; optionally request `gmail.send`.
4. Create a Desktop app OAuth client and download the JSON. The wizard rejects Web clients and service accounts.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/operations.md (reported line 86)May include surrounding context.

User services normally follow the user login manager. Optional unattended boot support requires the user's terminal:

bash
sudo loginctl enable-linger "$USER"

This does not prevent suspend, restore internet, or change gateway startup settings. A laptop can miss timely alerts while asleep; history catch-up happens after resuming, subject to Google's retention.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gmail_connect.py (reported line 20)May include surrounding context.

python
version=None
    if binary:
        try:
            r=subprocess.run([binary,'--version'],capture_output=True,text=True,timeout=20)
            version=r.stdout.strip()[:200] if r.returncode==0 else 'Version probe failed'
        except subprocess.TimeoutExpired:version='Version probe timed out'
    osrel=Path('/etc/os-release')

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gmail_connect/service.py (reported line 14)May include surrounding context.

python
def run(args):
    try:
        result=subprocess.run(args, capture_output=True,text=True,timeout=15,check=False)
    except (OSError,subprocess.TimeoutExpired):
        raise Problem('User service manager is unavailable. Run the wizard in an Ubuntu desktop login session.') from None
    if result.returncode:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gmail_connect/service.py (reported line 28)May include surrounding context.

python
def enabled_state():
    try:
        result=subprocess.run(['systemctl','--user','is-enabled',UNIT],capture_output=True,text=True,timeout=5)
        return result.stdout.strip()
    except (OSError,subprocess.TimeoutExpired):
        raise Problem('Cannot inspect the existing user-service state.') from None

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

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

python
def status():
    if not shutil.which('systemctl'):return {'available':False,'active':False}
    try:
        r=subprocess.run(['systemctl','--user','is-active',UNIT],capture_output=True,text=True,timeout=5)
        return {'available':True,'active':r.returncode==0}
    except (OSError,subprocess.TimeoutExpired):return {'available':False,'active':False}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The install flow writes a persistent user systemd unit and immediately enables and starts it, creating ongoing background execution and autostart behavior. In a skill that connects to Gmail and monitors a mailbox, this persistence is security-relevant because it can continue accessing mail data after the initial user action unless the user clearly understands and consents to the service installation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The stop function disables and stops the user service via systemctl --user disable --now, changing persistent service state. There is no prompt, logging, or explanatory comment warning the user that this operation removes automatic startup behavior.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_package.py:11