T09 · Insecure Skill Coding Practices
- Location
news_aggregator.py:171- Finding
Untrusted news content is incorporated into an instruction-bearing AI prompt
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a disclosed news-to-Discord skill, but it needs review because it automatically posts AI-generated summaries from untrusted web and social content to Discord.
Install only if you expect this skill to send your requested topics and gathered article, tweet, and video metadata to third-party providers and post generated text to a configured Discord channel. Use dry-run first, provide only the API keys needed for the chosen mode, avoid sensitive topics, and prefer a version with pinned dependencies plus Discord mention/link validation.
news_aggregator.py:171Untrusted news content is incorporated into an instruction-bearing AI prompt
news_aggregator.py:2Automatically installed Python dependencies are not version-pinned
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
OpenClaw passes env vars declared in SKILL.md requires.env automatically.
AI provider selection (pick one):
Provider Env var needed Default model
───────── ────────────────────── ─────────────────────────
deepseek DEEPSEEK_API_KEY deepseek-chat
openai OPENAI_API_KEY gpt-4o-mini
claude ANTHROPIC_API_KEY claude-3-5-haiku-20241022
Set AI_PROVIDER=<provider> env var, or pass --provider flag at runtime.
Override model with AI_MODEL=<model> env var or --model flag.
External endpoints contacted:
- https://api.deepseek.com/chat/completions (provider=deepseek)
- https://api.openai.com/v1/chat/completions (provider=openai)
- https://api.anthropic.com/v1/messages (provider=claude)
- https://discord.com/api/webhooks/... (always, required)
- https://techcrunch.com/.../feed/ (defa
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return []
print(f" Fetching Tavily: '{topic}' (last {days}d)")
try:
resp = requests.post(
"https://api.tavily.com/search",
json={
"api_key": TAVILY_API_KEY,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return []
print(f" Fetching Twitter: '{topic}'")
try:
resp = requests.get(
"https://api.twitterapi.io/twitter/tweet/advanced_search",
headers={"X-API-Key": TWITTER_API_KEY},
params={"query": topic, "queryType": "Top"},
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
stats_map = {}
for i in range(0, len(video_ids), 50):
try:
resp = requests.get(
"https://www.googleapis.com/youtube/v3/videos",
params={
"part": "statistics,contentDetails",
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
resolved = {}
for handle in handles:
try:
resp = requests.get(
"https://www.googleapis.com/youtube/v3/channels",
params={
"part": "contentDetails,snippet",
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
for handle, (_, playlist_id) in handle_map.items():
display = AI_YOUTUBE_CHANNELS.get(handle, handle)
try:
resp = requests.get(
"https://www.googleapis.com/youtube/v3/playlistItems",
params={
"part": "snippet",
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
print(f" Searching YouTube: '{topic}'")
published_after = cutoff.strftime("%Y-%m-%dT%H:%M:%SZ")
try:
resp = requests.get(
"https://www.googleapis.com/youtube/v3/search",
params={
"part": "snippet",
The skill description understates and misstates important behavior, especially around what sources are actually used and the fact that it performs broad third-party network access and Discord posting. Description/behavior mismatches are dangerous because users may consent to one workflow while the skill executes another, increasing the chance of unintended data transmission or trust abuse.
Allowing runtime selection of external providers and models increases the attack surface and data-governance risk because the destination handling user content can change per invocation. Without strict policy controls, a user or prompt may steer data to a less-trusted provider than the operator intended, causing unapproved external disclosure.
uv run "$SCRIPT" --topic "climate change" --days 7 --provider claude
# Use a specific model
uv run "$SCRIPT" --topic "Bitcoin" --provider openai --model gpt-4o
# Trending AI on Twitter and YouTube
uv run "$SCRIPT" --report trending
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
AI : OpenAI (default) · DeepSeek · Anthropic Claude — user's choice
Output : Discord channel via webhook (formatted markdown)
Credentials: read from environment variables only (no .env file loaded).
OpenClaw passes env vars declared in SKILL.md requires.env automatically.
AI provider selection (pick one):
The skill declares no explicit tool scope or permissions even though it clearly needs environment-variable access and broad outbound network access to multiple third parties, including a Discord webhook. Missing scope declarations weaken platform-level safety controls because users and orchestrators cannot reliably constrain or review what the skill is allowed to do before execution.
The trigger text is overly broad, causing the skill to activate on common phrases like requests for news, digests, trending topics, or updates on any subject. Overbroad activation is risky because it can cause unintended execution of a networked skill that sends content to external services, including Discord, when the user may have only been asking conversationally.
This skill sends fetched content and user-selected topics to OpenAI for summarization, which is an external transmission to a third-party model provider. In context this is expected functionality, but it remains a real data-exposure risk if sensitive prompts, private topics, or proprietary feed content are included without clear consent or minimization.
| Endpoint | Purpose | Condition |
|----------|---------|-----------|
| `https://api.openai.com/v1/chat/completions` | AI editorial summarisation | Only if `provider=openai` (default) |
| `https://api.deepseek.com/chat/completions` | AI editorial summarisation | Only if `provider=deepseek` |
| `https://api.anthropic.com/v1/messages` | AI editorial summarisation | Only if `provider=claude` |
| `https://discord.com/api/webhooks/...` | Post digest to Discord | Always (required) |
This skill can transmit content externally to DeepSeek for summarization when that provider is selected. Although this is part of the advertised feature set, it still creates third-party data handling risk and may expose user interests, collected article text, or other contextual data beyond the local environment.
| Endpoint | Purpose | Condition |
|----------|---------|-----------|
| `https://api.openai.com/v1/chat/completions` | AI editorial summarisation | Only if `provider=openai` (default) |
| `https://api.deepseek.com/chat/completions` | AI editorial summarisation | Only if `provider=deepseek` |
| `https://api.anthropic.com/v1/messages` | AI editorial summarisation | Only if `provider=claude` |
| `https://discord.com/api/webhooks/...` | Post digest to Discord | Always (required) |
| `https://techcrunch.com/.../feed/` | RSS news (AI topic) | Default AI topic only |
This skill can transmit content externally to Anthropic when Claude is selected, which constitutes third-party disclosure of gathered material and user-request context. The behavior is expected but still security-relevant because model-provider transfers can leak sensitive or regulated data if not constrained.
|----------|---------|-----------|
| `https://api.openai.com/v1/chat/completions` | AI editorial summarisation | Only if `provider=openai` (default) |
| `https://api.deepseek.com/chat/completions` | AI editorial summarisation | Only if `provider=deepseek` |
| `https://api.anthropic.com/v1/messages` | AI editorial summarisation | Only if `provider=claude` |
| `https://discord.com/api/webhooks/...` | Post digest to Discord | Always (required) |
| `https://techcrunch.com/.../feed/` | RSS news (AI topic) | Default AI topic only |
| `https://www.theverge.com/rss/...` | RSS news (AI topic) | Default AI topic only |
The skill performs external transmission to Tavily for custom-topic searches, exposing user-requested topics and query context to a third-party search API. This is less severe than credential leakage, but it still matters because user interests or operational research topics may be sensitive.
| `https://techcrunch.com/.../feed/` | RSS news (AI topic) | Default AI topic only |
| `https://www.theverge.com/rss/...` | RSS news (AI topic) | Default AI topic only |
| `https://www.nytimes.com/svc/collections/...` | RSS news (AI topic) | Default AI topic only |
| `https://api.tavily.com/search` | Custom topic news search | Only if `TAVILY_API_KEY` set |
| `https://api.twitterapi.io/twitter/tweet/advanced_search` | Twitter search | Only if `TWITTERAPI_IO_KEY` set |
| `https://www.googleapis.com/youtube/v3/...` | YouTube search | Only if `YOUTUBE_API_KEY` set |
The skill can send queries to a third-party Twitter/X search API, revealing user interests and potentially generating externally visible or provider-logged lookups. In a general news skill this is contextually expected, but still constitutes a real outbound data flow that should be constrained and disclosed.
| `https://www.theverge.com/rss/...` | RSS news (AI topic) | Default AI topic only |
| `https://www.nytimes.com/svc/collections/...` | RSS news (AI topic) | Default AI topic only |
| `https://api.tavily.com/search` | Custom topic news search | Only if `TAVILY_API_KEY` set |
| `https://api.twitterapi.io/twitter/tweet/advanced_search` | Twitter search | Only if `TWITTERAPI_IO_KEY` set |
| `https://www.googleapis.com/youtube/v3/...` | YouTube search | Only if `YOUTUBE_API_KEY` set |
Exactly one AI endpoint is contacted per run, determined by the active provider. The default provider is OpenAI (`OPENAI_API_KEY` required). Switch providers with `--provider deepseek` or `--provider claude`.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Override model with AI_MODEL=<model> env var or --model flag.
External endpoints contacted:
- https://api.deepseek.com/chat/completions (provider=deepseek)
- https://api.openai.com/v1/chat/completions (provider=openai)
- https://api.anthropic.com/v1/messages (provider=claude)
- https://discord.com/api/webhooks/... (always, required)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
External endpoints contacted:
- https://api.deepseek.com/chat/completions (provider=deepseek)
- https://api.openai.com/v1/chat/completions (provider=openai)
- https://api.anthropic.com/v1/messages (provider=claude)
- https://discord.com/api/webhooks/... (always, required)
- https://techcrunch.com/.../feed/ (default AI topic only)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
External endpoints contacted:
- https://api.deepseek.com/chat/completions (provider=deepseek)
- https://api.openai.com/v1/chat/completions (provider=openai)
- https://api.anthropic.com/v1/messages (provider=claude)
- https://discord.com/api/webhooks/... (always, required)
- https://techcrunch.com/.../feed/ (default AI topic only)
- https://www.theverge.com/rss/... (default AI topic only)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
- https://techcrunch.com/.../feed/ (default AI topic only)
- https://www.theverge.com/rss/... (default AI topic only)
- https://www.nytimes.com/svc/collections/... (default AI topic only)
- https://api.tavily.com/search (only if TAVILY_API_KEY set)
- https://api.twitterapi.io/... (only if TWITTERAPI_IO_KEY set)
- https://www.googleapis.com/youtube/v3/... (only if YOUTUBE_API_KEY set)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
- https://techcrunch.com/.../feed/ (default AI topic only)
- https://www.theverge.com/rss/... (default AI topic only)
- https://www.nytimes.com/svc/collections/... (default AI topic only)
- https://api.tavily.com/search (only if TAVILY_API_KEY set)
- https://api.twitterapi.io/... (only if TWITTERAPI_IO_KEY set)
- https://www.googleapis.com/youtube/v3/... (only if YOUTUBE_API_KEY set)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
- https://www.theverge.com/rss/... (default AI topic only)
- https://www.nytimes.com/svc/collections/... (default AI topic only)
- https://api.tavily.com/search (only if TAVILY_API_KEY set)
- https://api.twitterapi.io/... (only if TWITTERAPI_IO_KEY set)
- https://www.googleapis.com/youtube/v3/... (only if YOUTUBE_API_KEY set)
CLI flags:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
- https://www.theverge.com/rss/... (default AI topic only)
- https://www.nytimes.com/svc/collections/... (default AI topic only)
- https://api.tavily.com/search (only if TAVILY_API_KEY set)
- https://api.twitterapi.io/... (only if TWITTERAPI_IO_KEY set)
- https://www.googleapis.com/youtube/v3/... (only if YOUTUBE_API_KEY set)
CLI flags:
The function name and prompt explicitly require generating an English editorial, including the instruction 'Write a 150-200 word editorial paragraph' with no option for user language selection. This is a natural-language policy issue because the skill imposes a specific language rather than offering locale choice or documenting a justified region-specific constraint.