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.
