Back to skill

Security audit

Daily Medium

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Medium-digest purpose, but it handles Gmail app-password credentials in an overbroad way that could expose a user's mailbox credentials if misused.

Review carefully before installing. Use only in an environment you trust, prefer a dedicated or easily revocable credential, revoke the Gmail app password after use, and avoid exposing EMAIL_PASSWORD where unrelated tools or prompts can influence calls. The imap_server parameter should be removed or strictly allowlisted to imap.gmail.com before this is treated as safe for normal use.

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

Error
Location
scripts/fetch_medium.py:41
Finding
Caller-Controlled IMAP Server Can Receive Gmail Credentials## Vulnerability Details **File Location**: `scripts/fetch_medium.py:41-70` **Vulnerability Type**: Credential disclosure through a caller-controlled authentication endpoint **Risk Level**: High ### Vulnerable Code ```python def fetch_medium_digest( email_address=None, password=None, imap_server="imap.gmail.com", max_articles=15 ): """ Fetch Medium Daily Digest emails from Gmail. Args: email_address: Gmail address (defaults to EMAIL_ADDRESS env var) password: App password (defaults to EMAIL_PASSWORD env var) imap_server: IMAP server address max_articles: Maximum number of articles to return Returns: List of article dictionaries with title, author, url """ # Get credentials from environment if not provided email_address = email_address or os.environ.get('EMAIL_ADDRESS') password = password or os.environ.get('EMAIL_PASSWORD') if not email_address or not password: raise ValueError("Email credentials required. Set EMAIL_ADDRESS and EMAIL_PASSWORD env vars.") try: # Connect to Gmail mail = imaplib.IMAP4_SSL(imap_server) mail.login(email_address, password) ``` ### Technical Analysis The function obtains a Gmail address and app password from its arguments or environment variables, but allows the caller to choose the IMAP server receiving those credentials. `imaplib.IMAP4_SSL` validates the TLS connection, but TLS only protects credentials in transit to the selected server. It does not establish that the destination is Gmail. Consequently, an attacker-controlled IMAP service with a valid TLS certificate can receive the Gmail address and app password when `mail.login()` is called. Because the declared functionality is specifically limited to fetching a Gmail-hosted Medium digest, permitting arbitrary authentication destinations exceeds the minimu ...[truncated 1521 chars]
Remediation
## Remediation Suggestions 1. Remove the `imap_server` parameter because this Skill is explicitly designed for Gmail, and always connect to the fixed destination `imap.gmail.com`. 2. If server configurability is essential, enforce an exact hostname allowlist before loading credentials. Reject IP literals, alternative domains, user-info syntax, and subdomain suffix tricks. 3. Do not allow redirects or fallback authentication to any unapproved host. 4. Prefer Gmail OAuth 2.0 with narrowly scoped, short-lived, and revocable tokens instead of reusable app passwords. 5. Separate credential retrieval from endpoint selection so credentials are loaded only after the destination has passed validation. 6. Add automated tests confirming that values such as `attacker.example`, `imap.gmail.com.attacker.example`, and direct IP addresses are rejected before any network connection or authentication attempt. 7. Update `SKILL.md` to discourage passing credentials directly in source code and to document the exact approved authentication destination. 8. Ensure logout and connection cleanup occur in a `finally` block so exceptional paths do not leave authenticated sessions open.
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 (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared behavior understates sensitive operations: the skill requires Gmail credentials and inbox access without corresponding permission declarations, while summarization is only shown as example code rather than implemented behavior. This mismatch can mislead users into granting access to private email content without a clear understanding of what the skill actually does and what external services may receive derived data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill describes use of environment variables and networked access to Gmail/IMAP and a third-party site, but it declares no explicit tool scope or permissions. This weakens least-privilege controls and can cause users or hosting systems to underestimate that the skill needs mailbox access and outbound network capability.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill instructs users to provide Gmail address and app password and to enable IMAP, but it does not warn that it will access privacy-sensitive mailbox contents. Even if intended only for a specific digest email, mailbox credentials are highly sensitive and could expose broader inbox data if mishandled or if the implementation is extended or compromised.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill fetches article content through a third-party mirror service intended to bypass Medium's paywall, but it does not warn users that article URLs and request metadata will be sent to an external domain. This creates privacy, trust, and legal/compliance risks, especially because users may assume the skill only interacts with Gmail and Medium.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The manifest describes fetching and summarizing Medium Daily Digest emails from Gmail, but this implementation implicitly reaches into process environment variables to obtain sensitive credentials. Reading secrets from the environment is not mentioned in the skill description and is an additional sensitive capability beyond the user-facing purpose.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill accesses sensitive email credentials from environment variables without any user-facing disclosure, which can hide that the skill depends on privileged mailbox access. In an agent-skill context, undisclosed credential use increases the risk of users or operators granting broader access than they realize, especially since mailbox credentials expose far more than just Medium digests.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The code establishes an IMAP connection, logs into Gmail, selects the inbox, and searches mail without any visible consent or runtime warning. Even though it searches for Medium senders, the capability grants broad inbox access, so the hidden remote-account access is more dangerous in this skill context than a local-only parser would be.

Static analysis

No suspicious patterns detected.