Back to skill

Security audit

Email Newsletter Digest

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does what it says, but it can pull more Gmail content than the selected newsletters and automatically email summaries or failure details to configured recipients.

Review the configured labels, senders, recipients, and delivery mode before installing. Prefer individual delivery, avoid third-party recipients unless you are comfortable sharing newsletter-derived content with them, and be cautious scheduling recurring runs until the full-thread retrieval behavior is fixed or clearly acceptable for your mailbox.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/newsletter-digest.py:746
Finding

Entire Gmail Threads May Be Disclosed Beyond the Selected Message Scope

Content
View full analysis

Vulnerability Details

File Location: scripts/newsletter-digest.py:746-757, 788-791
Related Instruction: SKILL.md:79
Vulnerability Type: Excessive email retrieval and unintended disclosure to an external summarization provider
Risk Level: Medium

Complete Code Snippet

python
def fetch_message_body(message: dict[str, Any], account: str | None) -> str:
    message_id = str(message.get("id") or "")
    thread_id = str(message.get("threadId") or "")
    if not thread_id:
        return ""

    result = run_command(
        ["gog", "gmail", "thread", "get", thread_id, *build_account_args(account), "--full"],
        check=False,
    )
    body = result.stdout.strip() if result.returncode == 0 else ""
    if body and not looks_like_placeholder_body(body):
        return body

    try:
        fallback = fetch_best_message_body(message_id, account)
    except RuntimeError:
        fallback = ""
    return fallback or body
python
body = fetch_message_body(message, account)
if not body:
    body = "[Could not fetch content]"

temp_file = temp_dir / f"newsletter-{message_id}.html"
temp_file.write_text(body)

log(f"[{index}/{len(messages)}] Summarizing...")
outcome = summarize_text(temp_file, model, prompt)

The behavior is also explicitly required by the Skill instructions:

markdown
- Use `gog gmail thread get --full` first for body extraction.

Technical Analysis

The Gmail search identifies individual messages matching configured newsletter labels or sender addresses and limits the search with newer_than:1d. However, body extraction does not initially retrieve only the matched message. Instead, it invokes gog gmail thread get <threadId> --full and treats the command's complete output as the content to summarize.

A Gmail thread can contain content outside the intended selection boundary, including:

  • Older messages that do not satisfy newer_than:1d
  • User replies and private annotations
  • Forwarded messages ...[truncated 2687 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace full-thread retrieval with message-specific retrieval:

    python
    ["gog", "gmail", "get", message_id, *build_account_args(account), "--json"]
    

    Extract only the MIME body belonging to the exact message ID returned by the search.

  2. Make the existing fetch_best_message_body() message-specific path the primary retrieval mechanism rather than a fallback.

  3. If thread retrieval is operationally unavoidable:

    • Parse the thread into individual messages.
    • Select only the message whose ID equals the search result's message ID.
    • Reapply the one-day boundary before processing.
    • Reject messages that do not independently satisfy the configured sender or label scope.
    • Remove quoted history and forwarded-message sections before summarization.
  4. Apply content minimization before invoking summarize:

    • Strip unnecessary headers, tracking data, signatures, and quoted replies.
    • Submit only the newsletter body required to produce the digest.
    • Avoid including unrelated thread metadata.
  5. Clearly disclose that newsletter content is sent to the configured summarization provider and obtain informed user consent before external processing.

  6. Add regression tests using a thread containing an old sensitive message and a recent matching newsletter message. Verify that only the recent matched message reaches the summarizer.

  7. Retain temporary-directory cleanup, but create files with explicitly restrictive permissions where portability permits and ensure cleanup also occurs when subprocess execution fails.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill’s declared purpose understates sensitive behavior: it reads Gmail message bodies, sends outbound emails, and may send separate warning or failure notifications. This mismatch is dangerous because users may invoke the skill expecting summarization only, without realizing it performs additional message access and outbound communications to potentially multiple recipients.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/newsletter-digest.py (reported line 335)May include surrounding context.

python
def summarize_text(file_path: Path, model: str | None, prompt: str) -> SummaryOutcome:
    env = os.environ.copy()
    args = [
        "summarize",
        str(file_path),

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The reference explicitly supports a group delivery mode that places every configured recipient in the same To field, but it does not warn users that all recipient email addresses will be disclosed to one another. In a skill designed for natural-language emailing to 'me and my friends,' that omission can easily lead to unintended privacy exposure, especially when recipients are not expecting shared disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The scheduling guidance says the platform should use its normal scheduler for recurring digest delivery, but it does not clearly warn that future runs may send emails automatically without per-run confirmation. Because this skill sends outbound email and can target multiple recipients, users may unknowingly authorize ongoing communications, creating privacy, spam, or reputational risk if settings later become stale or overly broad.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill declares executable capabilities including shell, file read/write, and environment access, but does not declare any explicit tool scope or permissions. That creates a governance gap where a user or reviewer cannot easily tell that the skill can read settings, invoke external commands, and modify files, increasing the chance of unintended data access or command execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The trigger examples are broad enough to match common email or scheduling requests, which can cause the skill to activate outside a narrow newsletter-only context. Misrouting a generic email request into a skill that reads inbox content and sends mail can lead to unintended access or delivery actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The user-facing description does not clearly warn that the skill will send emails to configured recipients and may contact multiple people. That omission reduces informed consent and raises the risk of accidental disclosure or unintended outbound communication.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The settings mention 'group' delivery but omit that putting all recipients in the To field exposes each address to every other recipient. In a newsletter digest context, that can leak personal or business email addresses without the recipients’ expectation or consent.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
If the user asks to schedule it:
- use OpenClaw's normal scheduling or cron mechanism
- do not ask the user to write shell commands
- if the user says "every morning" and does not specify a time, use a reasonable morning time in the system timezone

## Core Rules

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/newsletter-digest.py (reported line 138)May include surrounding context.

python
check: bool = True,
    input_text: str | None = None,
) -> subprocess.CompletedProcess[str]:
    result = subprocess.run(
        args,
        input=input_text,
        capture_output=True,

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill automatically collects email content, sender addresses, and failure details from a user's mailbox and forwards derived summaries to configured recipients, who may include third parties. In this skill context, that is the core feature, but it still creates a real confidentiality risk because private or unexpectedly sensitive newsletter content and metadata can be redistributed without per-message consent or content classification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.