T09 · Insecure Skill Coding Practices
- Location
scripts/pubmed_intent_handler.py:48- Finding
Unrestricted LLM Endpoint Can Receive API Credentials and Sensitive Medical Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to be a real PubMed review tool, but it has unsafe configuration and execution paths that need review before installation.
Install only in a controlled environment after fixes or compensating controls: pin MINIMAX_API_URL to an approved HTTPS host, parse env files as data rather than shell code, validate task IDs and article paths, restrict NOTIFY_PATH to a trusted binary, and run any dispatcher or cron job as a dedicated unprivileged user. Treat user queries and article abstracts as content that may leave the local environment for MiniMax and Feishu.
scripts/pubmed_intent_handler.py:48Unrestricted LLM Endpoint Can Receive API Credentials and Sensitive Medical Content
scripts/run_pubmed_summary.sh:26Configurable Environment File Is Executed as Shell Code
scripts/run_pubmed_summary.sh:58Command-Line Arguments Are Interpolated into Inline Python Source
scripts/pubmed_intent_handler.py:275Predictable Temporary File Permits Symlink-Based File Overwrite
The destination URL for the LLM request is environment-controlled via MINIMAX_API_URL, and the request includes sensitive content plus the Bearer API key. If an attacker can alter that variable, they can redirect requests to an arbitrary server and exfiltrate both the user's question/article data and credentials, effectively turning this into SSRF-plus-secret-leakage.
method='POST'
)
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read().decode('utf-8'))
msg = result['choices'][0]['message']
content = msg.get('content', '') or msg.get('reasoning_content', '')
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
method='POST'
)
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read().decode('utf-8'))
msg = result['choices'][0]['message']
content = msg.get('content', '') or msg.get('reasoning_content', '')
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
method='POST'
)
with urllib.request.urlopen(req, timeout=60) as resp:
result = json.loads(resp.read().decode('utf-8'))
msg = result['choices'][0]['message']
content = msg.get('content', '') or msg.get('reasoning_content', '')
This mismatch is security-relevant because the skill is presented as a narrow literature-review workflow but reportedly also performs local task queue persistence and subprocess execution. Hidden or under-documented file and shell behavior can cause reviewers to underestimate operational risk and approve broader access than intended.
This mismatch is security-relevant because the skill is presented as a narrow literature-review workflow but reportedly also performs local task queue persistence and subprocess execution. Hidden or under-documented file and shell behavior can cause reviewers to underestimate operational risk and approve broader access than intended.
This mismatch is security-relevant because the skill is presented as a narrow literature-review workflow but reportedly also performs local task queue persistence and subprocess execution. Hidden or under-documented file and shell behavior can cause reviewers to underestimate operational risk and approve broader access than intended.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
{articles_text}
请开始撰写:"""
return prompt
def call_llm(prompt):
The README describes activation via ordinary natural-language messages in Feishu and gives examples like '帮我查…' and '帮我搜索…', but it does not define a strict trigger list, exclusion conditions, or when similar everyday phrasing should not invoke the skill. This ambiguity can cause unintended invocation because these phrases overlap with common conversational requests.
The skill documents capabilities that imply access to environment variables, filesystem, network, and shell execution, but it does not declare any explicit tool scope or permissions boundaries. This increases the blast radius if the skill is invoked in a permissive runtime, because operators and users cannot readily tell what external effects or privileged actions it may perform.
The natural-language trigger description is overly broad and lacks clear boundaries for when the skill should activate. In chat-integrated systems, ambiguous triggering can cause unintended execution, unnecessary data transmission, or accidental use of external APIs on messages that the user did not intend as PubMed requests.
The skill description does not clearly warn that user queries and generated outputs may be sent to external services and push-notified through Feishu. This is dangerous because literature queries can contain sensitive research interests, internal project context, or regulated information, and users may not realize their content is leaving the local environment.
The skill sends content to an external LLM endpoint, which creates a real data exfiltration and privacy risk if user queries, article summaries, or follow-up content contain sensitive information. In this skill context, the risk is elevated because medical/research topics and generated reviews may reveal confidential interests or internal analyses, and the transmission is only implicitly documented.
| 变量名 | 必须 | 说明 |
|--------|------|------|
| `MINIMAX_API_KEY` | ✅ | MiniMax API Key |
| `MINIMAX_API_URL` | 否 | 默认为 `https://api.minimax.chat/v1/text/chatcompletion_v2` |
| `MINIMAX_MODEL` | 否 | 默认为 `MiniMax-M2.7-highspeed` |
| `NOTIFY_PATH` | 否 | 飞书 notify 脚本路径,默认为 `which notify` |
| `MINIMAX_ENV_FILE` | 否 | 环境变量文件路径,默认为 `./.env.minimax` |
Automatic trigger conditions are described vaguely, without specifying when the skill should or should not run. This can lead to accidental activation in Feishu/OpenClaw contexts, exposing user text to external services or creating tasks without clear user consent.
The skill is described as handling PubMed retrieval, AI review generation, Feishu notification, and follow-up Q&A. Mentioning 'Cookie 失效' handling implies the skill also monitors or depends on browser/session cookie state, which is not justified anywhere else in the stated purpose and is not an obvious implementation detail for PubMed E-utilities or LLM summarization.
The script reads an environment-specified file and imports every KEY=VALUE pair into process environment variables without validating the path, ownership, or contents. In a shared or attacker-influenced deployment, this creates a configuration-injection surface that can alter API endpoints, credentials, or downstream behavior, enabling issues like the arbitrary endpoint and notifier-path abuses seen elsewhere in the file.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
load_llm_env()
LLM_API_URL = os.environ.get('MINIMAX_API_URL', 'https://api.minimax.chat/v1/text/chatcompletion_v2')
LLM_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
LLM_MODEL = os.environ.get('MINIMAX_MODEL', 'MiniMax-M2.7-highspeed')
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
load_llm_env()
LLM_API_URL = os.environ.get('MINIMAX_API_URL', 'https://api.minimax.chat/v1/text/chatcompletion_v2')
LLM_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
LLM_MODEL = os.environ.get('MINIMAX_MODEL', 'MiniMax-M2.7-highspeed')
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
load_llm_env()
LLM_API_URL = os.environ.get('MINIMAX_API_URL', 'https://api.minimax.chat/v1/text/chatcompletion_v2')
LLM_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
LLM_MODEL = os.environ.get('MINIMAX_MODEL', 'MiniMax-M2.7-highspeed')
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
load_llm_env()
LLM_API_URL = os.environ.get('MINIMAX_API_URL', 'https://api.minimax.chat/v1/text/chatcompletion_v2')
LLM_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
LLM_MODEL = os.environ.get('MINIMAX_MODEL', 'MiniMax-M2.7-highspeed')
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
load_llm_env()
LLM_API_URL = os.environ.get('MINIMAX_API_URL', 'https://api.minimax.chat/v1/text/chatcompletion_v2')
LLM_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
LLM_MODEL = os.environ.get('MINIMAX_MODEL', 'MiniMax-M2.7-highspeed')
The handler sends the user's follow-up question plus article titles and abstracts to the remote endpoint configured by LLM_API_URL. While the network call is visible in code, there is no confirmation prompt or user-facing disclosure here that their content will be transmitted to a third-party service.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def notify_user(message):
"""发送飞书消息"""
subprocess.run(
[NOTIFY_SCRIPT, '-t', '综述追问回复', '-m', message],
shell=False
)
The executable path for subprocess.run comes from the NOTIFY_PATH environment variable, so anyone able to influence the runtime environment can cause the script to execute an arbitrary program. Because this handler may run with the privileges of the hosting agent/service, that becomes a code-execution primitive rather than a harmless configuration choice.
def notify_user(message):
"""发送飞书消息"""
subprocess.run(
[NOTIFY_SCRIPT, '-t', '综述追问回复', '-m', message],
shell=False
)
The skill includes capability to invoke an external notification executable selected by environment-controlled path, which expands it from PubMed intent handling into local program execution. In an agent setting, unnecessary execution capabilities increase attack surface and can be abused for lateral actions unrelated to the stated purpose.
The full user message is transmitted to an external LLM service for intent recognition without any visible consent, minimization, or redaction. Users may include medical, personal, or confidential research content, making this a meaningful privacy and data-handling issue in the skill context.
No suspicious patterns detected.