T09 · Insecure Skill Coding Practices
- Location
SKILL.md:30- Finding
Plaintext credential storage in shell startup files or crontab is recommended
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill fits a news-aggregation purpose, but it needs review because it posts untrusted news reports to external webhooks and gives weak secret-storage guidance.
Install only if you are comfortable sending selected news topics, titles, translations, summaries, and error details to the configured third-party services. Use trusted RSS feeds, a dedicated low-privilege Feishu bot, avoid putting secrets directly in ~/.bashrc or crontab, and consider patching the skill to validate URLs, escape Markdown, and support a local-only mode before scheduled use.
SKILL.md:30Plaintext credential storage in shell startup files or crontab is recommended
daily-news.sh:125Untrusted RSS content is embedded into Feishu Markdown without validation
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# 打印发送的 JSON 用于调试
print("发送的 JSON:", card)
resp = requests.post(WEBHOOK_URL, json=card)
print(f"✅ 分析报告已推送,状态码: {resp.status_code}")
print("响应内容:", resp.text)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
}
try:
resp = requests.post(WEBHOOK_URL, json=card)
print(f"趋势报告已推送,状态码: {resp.status_code}")
except Exception as e:
print(f"推送失败: {e}")
The skill explicitly sends fetched news content to external services: titles/content are transmitted to Baidu Translate, RSS data is pulled from external sources, and results may be posted to a Feishu group. Because the description does not clearly warn users that third parties may receive potentially sensitive keywords, article titles, or generated summaries, users may unknowingly expose business interests or internal monitoring topics to outside services.
No manifest is available, so there is no declared purpose establishing that sending processed news data to a remote webhook is intended. The code reads a local news file, formats its contents, and posts the resulting report to an externally configured URL, which is a materially broader capability than simple local classification.
The script uses Chinese-only user-facing messages and category labels, including error text, report headers, and summaries, with no option for the user to select another language. This creates a natural-language locale policy issue because the skill implicitly forces Chinese output rather than offering opt-in or documenting that the skill is intentionally Chinese-only.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 打印发送的 JSON 用于调试
print("发送的 JSON:", card)
resp = requests.post(WEBHOOK_URL, json=card)
print(f"✅ 分析报告已推送,状态码: {resp.status_code}")
print("响应内容:", resp.text)
Comments, status messages, errors, and output headings are written exclusively in Chinese, and the translation target is forced to zh. This imposes a specific language/locale without any opt-in mechanism or documented justification that the skill is intended only for Chinese-speaking users.
The file is documented as an '外贸资讯聚合器' (trade/foreign-trade news aggregator), but it also supports pulling top stories from Hacker News via the INCLUDE_HACKER_NEWS option. General technology-news scraping is not obviously justified by the stated trade-news purpose and expands the skill's capability beyond the described context.
Article titles are sent to Baidu's translation API, which is a third-party service, without any disclosure or consent mechanism. Even if titles are public, the selected set of content, keywords, and usage pattern can reveal business interests, monitoring priorities, or sensitive research topics.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if command -v xmlstarlet >/dev/null 2>&1; then
xmlstarlet sel -t -m "//item" -v "title" -o "||" -v "link" -o "||" -n "$tmp" 2>/dev/null
else
echo "错误:未安装 xmlstarlet,请运行 sudo apt install xmlstarlet -y" >&2
return 1
fi
rm "$tmp"
The script transmits runtime error details to an external Feishu webhook without any built-in consent, warning, or data minimization. Error messages can contain network details, feed URLs, file paths, or other operational context that may be sensitive in an enterprise environment.
This line performs an external POST of error information to a configurable webhook endpoint. Because the destination and contents are externally transmitted, this can leak operational details or be abused for unintended data exfiltration if the webhook is misconfigured or controlled by an untrusted party.
local error_msg="$1"
if [ -n "$FEISHU_WEBHOOK" ]; then
local json=$(jq -n --arg msg "❌ 外贸资讯聚合器运行失败\n\n错误详情: $error_msg" '{"msg_type":"text","content":{"text":$msg}}')
curl -X POST -H "Content-Type: application/json" -d "$json" "$FEISHU_WEBHOOK" > /dev/null 2>&1
fi
}
This line sends the full generated report to an external webhook, creating a clear exfiltration path for collected and transformed content. In a business setting, the aggregated topics and translations may reveal strategic interests or internal monitoring activity.
]
}
}')
curl -X POST -H "Content-Type: application/json" -d "$CARD_JSON" "$FEISHU_WEBHOOK" > /dev/null 2>&1
echo "✅ 已推送到飞书(卡片消息)"
fi
The generated report content is posted to Feishu via webhook without explicit disclosure in the script's primary behavior. This creates an external data-sharing path that could expose curated news selections, translated text, and organizational interests to a third-party messaging platform.
The file's comments and title describe a news aggregator, but at the end it triggers classify_news.py and trend_analysis.py, adding downstream classification and multi-day trend-analysis behavior. Those extra analytics capabilities are broader than straightforward aggregation and are not evident from the stated purpose in this file.
The skill requires a secret webhook from the environment and uses it to transmit derived local data off-host, but the provided context does not declare or justify this external reporting behavior. In agent environments, undeclared outbound channels are risky because they can silently export workspace-derived information to an external service.
This code emits user-facing messages in Chinese, indicating a fixed language choice rather than adapting to user preference. The file provides no opt-in, configuration, or documentation justifying a Chinese-only locale, which matches the language/locale policy violation criteria.
This code aggregates categories from a local file and history directory, then posts the resulting trend report to an external Feishu webhook. Even though the payload is summarized rather than raw content, it still constitutes exfiltration of locally derived information without any stated authorization boundary or consent mechanism.
The report title and console messages are all hard-coded in Chinese, and the skill does not expose any way for users to choose another language. Because this affects multiple user-visible outputs, it represents an ongoing locale policy issue rather than a single isolated string.
The skill performs an external HTTP POST to a webhook, sending data derived from local files to a third-party endpoint. In this context the transmission appears functional rather than overtly malicious, but undeclared outbound data flow from an agent skill is security-relevant because it can leak workspace information beyond the local trust boundary.
}
}
try:
resp = requests.post(WEBHOOK_URL, json=card)
print(f"趋势报告已推送,状态码: {resp.status_code}")
except Exception as e:
print(f"推送失败: {e}")