Back to skill

Security audit

Gmail Lead Monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill needs review because it can forward every new Gmail message snippet to Telegram, not just keyword-matched leads, and it stores Gmail and Telegram credentials in a plaintext local config file.

Install only if you are comfortable with Gmail message metadata and body snippets being sent to the configured Telegram chat for every unseen message processed, not just keyword matches. Use a dedicated Gmail app password, restrict config file permissions, keep the Telegram bot private, and avoid using this on mailboxes containing sensitive personal, financial, legal, or regulated information unless the behavior is fixed or tightly configured.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
gmail_monitor.py:226
Finding

Keyword Filtering Does Not Prevent Transmission of Unmatched Emails

Content
View full analysis
New Email\n" f"From: {sender}\n" f"Subject: {subject}\n" f"Time: {timestamp}\n" ) if snippet: msg += f"\n{snippet[:200]}...\n" ``` ### Technical Analysis The keyword check only determines whether an email is starred and how its alert is labeled. Regardless of the value of `important`, every fetched unseen message is appended to `new_emails`. `run_once()` subsequently sends every entry in that list to Telegram. Consequently, sender details, subject lines, timestamps, and up to 200 characters of message-body content are transmitted to `api.telegram.org` even when an email does not match any configured keyword. This exceeds the minimum data transmission necessary for the documented keyword-filtered lead-monitoring function. The project documentation describe ...[truncated 1635 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
gmail_monitor.py:127
Finding

Unescaped Email Content Is Interpreted as Telegram HTML

Content
View full analysis
bool: """Send Telegram message. Returns True on success.""" url = f"https://api.telegram.org/bot{token}/sendMessage" payload = json.dumps({ "chat_id": chat_id, "text": message, "parse_mode": "HTML" }).encode("utf-8") req = urllib.request.Request( url, data=payload, headers={"Content-Type": "application/json"}, method="POST" ) try: with urllib.request.urlopen(req, timeout=10) as r: return r.status == 200 except urllib.error.HTTPError as e: print(f"[gmail] Telegram error {e.code}: {e.read().decode()[:100]}") return False except Exception as e: print(f"[gmail] Telegram error: {e}") return False ``` ```python def format_alert(sender: str, subject: str, snippet: str, timestamp: str, is_important: bool, keyword: str) -> str: """Format Telegram alert message.""" icon = "📧⭐" if is_important else "📧" msg = ( f"{icon} New Email\n" f"From: {sender}\n" f"Subject: {subject}\n" f"Time: {timestamp}\n" ) if snippet: msg += f"\n{snippet[:200]}...\n" if is_important: msg += f"\n⭐ Flagged as important (keyword: {keyword})" return msg ``` ### Technical Analysis Telegram is instructed to interpret each alert using HTML parse mode. However, the application inserts dynamic values directly into the HTML-formatted message without escaping them. Attacker-controlled or externally controlled values include: - Email sender headers - Email subject lines - Email body snippets - Email timestamps The configured keyword is als ...[truncated 1951 chars]
Remediation
View remediation
`, `&`, quotes, and Telegram-supported tags. 2. Avoid treating delivery failure as successful processing. 3. Add a retry queue or mark a message as seen only after successful alert delivery. 4. Keep trusted formatting templates separate from all untrusted email data. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:22
Finding

Plaintext Gmail and Telegram Credentials Lack Permission Hardening

Content
View full analysis
~/.config/gmail_monitor/config.json << 'EOF' { "email": "you@gmail.com", "app_password": "xxxx xxxx xxxx xxxx", "telegram_token": "your_bot_token", "telegram_chat_id": "your_chat_id", "keywords": ["order", "purchase", "setup", "interested", "question", "invoice"], "check_interval_minutes": 5, "max_emails_per_check": 20 } EOF ``` The application reads the file without validating its ownership or permissions: ```python CONFIG_PATH = Path.home() / ".config" / "gmail_monitor" / "config.json" STATE_FILE = Path.home() / ".config" / "gmail_monitor" / "seen_ids.json" GMAIL_IMAP = "imap.gmail.com" GMAIL_PORT = 993 # ── Config ──────────────────────────────────────────────────────────────────── def load_config() -> dict: if not CONFIG_PATH.exists(): print(f"[gmail] Config not found: {CONFIG_PATH}") print("[gmail] Create it with: email, app_password, telegram_token, telegram_chat_id, keywords") sys.exit(1) with open(CONFIG_PATH) as f: return json.load(f) ``` ### Technical Analysis The configuration file contains a Gmail app password and Telegram bot token in plaintext. Plaintext configuration is sometimes operationally necessary, but the setup neither creates the directory and file with explicit restrictive modes nor instructs the user to apply `chmod 600`. The resulting access permissions depend on the user's current umask and filesystem environment. Under a permissive configuration, the file may be readable by other local users or processes. The application also does not verify that the file is owned by the current user or reject group-readable or world-readable p ...[truncated 1630 chars]
Remediation
View remediation
~/.config/gmail_monitor/config.json << 'EOF' { "email": "you@gmail.com", "app_password": "xxxx xxxx xxxx xxxx", "telegram_token": "your_bot_token", "telegram_chat_id": "your_chat_id" } EOF chmod 600 ~/.config/gmail_monitor/config.json ``` At application startup: 1. Use `os.stat()` to verify that the file is owned by the current user. 2. Warn or terminate if group or other permission bits are set. 3. Reject symbolic links where the deployment threat model includes local adversaries. 4. Prefer an operating-system credential store or secret manager where available. 5. Keep credentials out of logs and exception messages. 6. Document credential rotation procedures. 7. Revoke and regenerate both credentials immediately if unauthorized file access is suspected. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly sends email metadata and a body snippet to Telegram, but the description does not warn users that email content leaves Gmail and is transmitted to a third-party messaging platform. This can expose sensitive business inquiries, personal information, or regulated data to Telegram without informed consent, making the omission a real security/privacy issue in this context.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The setup instructs users to persist long-lived secrets including a Gmail app password and Telegram bot token in a plaintext JSON file under ~/.config. If local file permissions are weak, the host is shared, backups are exposed, or malware reads user files, these credentials can be stolen and used to access email or abuse the Telegram bot.

Content

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

  1. Go to App passwords → Generate new app password
  2. Select "Mail" and your device → Copy the 16-char password

2. Create Config File

bash
mkdir -p ~/.config/gmail_monitor

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level docstring says the tool monitors Gmail and sends Telegram alerts, but the implementation also modifies mailbox state by applying the IMAP \Flagged flag to matching emails. This mismatch is security-relevant because users may grant mailbox access expecting passive monitoring while the script performs undisclosed write actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script transmits sender, subject, timestamp, and a body snippet from emails to Telegram, an external third-party service, without strong user-facing disclosure or minimization controls. This can leak sensitive personal or business data from inbox contents, especially because keyword matching encourages forwarding potentially important messages that may contain confidential information.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This code sends alert contents to api.telegram.org, which is an external network destination outside Gmail and the local host. In the context of an inbox-monitoring skill, external transmission is only safe when clearly disclosed and tightly scoped; otherwise it creates a real data exfiltration path for email-derived content.

Content

Scanner excerpt · gmail_monitor.py (reported line 135)May include surrounding context.

python
def send_telegram(token: str, chat_id: str, message: str) -> bool:
    """Send Telegram message. Returns True on success."""
    url = f"https://api.telegram.org/bot{token}/sendMessage"
    payload = json.dumps({
        "chat_id": chat_id,
        "text": message,

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The check_gmail docstring states that it connects, fetches unseen emails, and returns new email data, but it also changes mailbox state by starring important messages. Hidden side effects are dangerous in automation because callers may reuse the function in contexts that assume read-only behavior and unintentionally alter user data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The code reads a Gmail app password from the config file and uses it for IMAP login, which is a sensitive credential operation. While the config example shows the field name, there is no explicit warning or comment about securely storing this credential or the sensitivity of the local config file.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.