T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/check_emails.py:127- Finding
AI API Credential Forwarded to an Unrelated License Validation Service
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This email assistant mostly matches its stated purpose, but it has under-disclosed handling of mailbox data and a serious credential-boundary issue that users should review before installing.
Review this skill before installing. Use a dedicated 91Skillhub license token only, do not rely on OPENAI_API_KEY for licensing, and rotate any credential that may have been passed to the validation endpoint. Only enable AI and Feishu processing for mailboxes where third-party handling of email content is approved, use narrow Feishu recipients or webhooks, and avoid cron deployment until dry-run and data-sharing controls are fixed.
scripts/check_emails.py:127AI API Credential Forwarded to an Unrelated License Validation Service
scripts/check_emails.py:221Dry-Run Option Does Not Enforce the Promised No-Push Behavior
scripts/reply_generator.py:118Untrusted Email Content Is Embedded Directly into AI Prompts
scripts/requirements.txt:1Unnecessary Standard-Library Name Dependency Creates Package Shadowing Risk
The documentation contains a material contradiction: it claims the skill is 'read-only' and does not send email, while earlier sections explicitly advertise reply generation and sending after user confirmation. This can mislead users and reviewers about the true capability boundary of the skill, causing unsafe deployment decisions or overbroad trust in a component that may perform outbound communications.
The listing says the skill fetches mailbox contents, uses external AI APIs for classification/reply generation, and sends alerts to Feishu, but it does not clearly warn users that email content and metadata may be transmitted to third-party services. In a customer-service email workflow, messages can contain sensitive personal, financial, or business information, so lack of explicit disclosure creates a real privacy and data-handling risk even if the feature is intentional.
The README explicitly describes pulling mailbox contents, classifying them with AI, generating replies, and pushing summaries to Feishu, but it does not clearly warn users that potentially sensitive email content will be transmitted to third-party services. This creates a real privacy and compliance risk because users may deploy the skill without understanding that customer emails could leave their environment and be processed externally.
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.
crontab -e
# 添加以下行:
# 0 * * * * cd /home/gem/workspace/agent/skills/email-customer-assistant/scripts && python check_emails.py >> /var/log/email_assistant.log 2>&1
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.
crontab -e
# 添加以下行:
# 0 * * * * cd /home/gem/workspace/agent/skills/email-customer-assistant/scripts && python check_emails.py >> /var/log/email_assistant.log 2>&1
This email-processing script performs unrelated token verification against an external service and falls back to reading OPENAI_API_KEY from the environment, causing a sensitive credential to be transmitted to a third party outside the apparent email-assistant workflow. That creates a covert data-exfiltration path for environment secrets and violates least surprise, especially because the key may belong to another service entirely.
Unread emails are fetched and then passed into classification, reply generation, and optional Feishu summary push without any consent gate or warning in this file. In the context of a mail assistant, this means potentially sensitive message content, sender data, and snippets may be disclosed to external AI or messaging services unexpectedly.
The CLI advertises a '--dry-run' mode as 'check only', but this flag is never used to suppress side effects. As written, processing still reaches Feishu push logic, so users may unintentionally send email-derived summaries to an external system when they explicitly requested a non-mutating run.
When AI classification is enabled, the code sends email subject and body/snippet content to a configured external OpenAI-compatible API. Email content commonly contains personal, financial, or account data, so transmitting it off-system without explicit disclosure, consent, or data-handling controls creates a real privacy and compliance risk.
The prompt interpolates untrusted email subject/body directly into the model instruction block, so a crafted email can include natural-language instructions that try to override the classifier prompt and force misclassification. While this does not directly execute code, it can undermine business workflow triage, suppress urgent messages, or manipulate prioritization decisions.
The module description and user-facing messages are written exclusively in Chinese, and generated notification text is hardcoded in Chinese throughout the file. There is no indication that the skill is intentionally restricted to a Chinese-speaking or China-specific deployment, nor any option for user language selection.
The code sends email-derived content to an external Feishu webhook endpoint without any built-in consent, notice, or data-minimization control. In a mail-handling skill, subjects, senders, summaries, and urgency indicators can contain sensitive business or personal data, so silent third-party transmission creates a real privacy and compliance risk.
The direct user-message API path transmits email-derived content plus a recipient identifier to Feishu's external API with no explicit warning or approval workflow. This expands disclosure risk because message content and routing metadata are sent outside the local environment and could violate data-handling expectations or policy.
The single-email push routine constructs messages containing sender, subject, date, summary, category, and optional reply suggestions, then transmits them to Feishu recipients. Because these fields are derived from potentially sensitive customer email, this is a concrete exfiltration path to external parties or overly broad internal audiences if webhook/user targets are misconfigured or compromised.
The daily digest aggregates multiple emails and sends subjects, senders, and categories in a batch to Feishu, increasing the blast radius of a single outbound message. Bulk summaries amplify exposure because one push can disclose many customers' or incidents' details to unintended recipients, making misconfiguration or unauthorized access more damaging.
This code performs state-changing IMAP operations by setting or clearing the \Seen flag, which affects mailbox state and can alter how messages are presented to the user. Although the methods have docstrings, there is no user-facing disclosure, confirmation, or warning around this potentially surprising modification of user data.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
self.provider = ai_config.get("provider", "openai")
self.api_key = ai_config.get("api_key", "")
self.model = ai_config.get("model", "gpt-4o-mini")
self.base_url = ai_config.get("base_url", "https://api.openai.com/v1")
self.max_tokens = ai_config.get("max_tokens", 1000)
self.temperature = ai_config.get("temperature", 0.7)
self.timeout = ai_config.get("timeout", 30)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
self.provider = ai_config.get("provider", "openai")
self.api_key = ai_config.get("api_key", "")
self.model = ai_config.get("model", "gpt-4o-mini")
self.base_url = ai_config.get("base_url", "https://api.openai.com/v1")
self.max_tokens = ai_config.get("max_tokens", 1000)
self.temperature = ai_config.get("temperature", 0.7)
self.timeout = ai_config.get("timeout", 30)
The module sends email-derived content, including sender, subject, category, and up to 2000 characters of body text, to an external LLM service without any in-function consent gate, redaction step, or user-facing disclosure. Because emails often contain sensitive personal, business, or confidential data, this creates a real privacy and data-handling risk if operators use the feature without explicit awareness or authorization.
The README is written entirely in Chinese and introduces the assistant in Chinese, while the skill itself claims multilingual reply generation. There is no statement that the skill is intentionally China-market-only or that users may opt into another interface language, which may conflict with language/locale choice expectations.
The multilingual support section states '中文 (zh) | 默认', which establishes a default language preference in the skill's behavior. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the user is clearly offered a choice or the locale constraint is justified.
Natural-language strings such as the module description, CLI description, and report text are all Chinese, with no indication that users can choose another language. This can violate language/locale policy when a skill forces one language by default without offering an opt-in or selection.
The natural-language descriptions, labels, and prompts in this file are presented in Chinese only, including the class/module description and AI prompt text. Under the stated policy, forcing a specific language without user opt-in or justification can be a language/locale policy violation.
Docstrings and user-visible messages such as connection and fetch errors are written in Chinese, which imposes a specific language on users without any opt-in or fallback. Under the language/locale policy, forcing a single language without choice can be a natural-language policy violation.
The prompt explicitly instructs the model to write in the selected language (用{lang_name}撰写), and the API defaults to Chinese when no language is specified. This creates a locale/language constraint without any built-in user choice or opt-in at the point of generation.
No suspicious patterns detected.