T09 · Insecure Skill Coding Practices
- Location
src/index.js:38- Finding
Gateway Credential Disclosure Through an Unvalidated Gateway URL
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely matches its Telegram digest purpose, but it needs review because it sends message text and a gateway token to configurable LLM endpoints while its privacy documentation is inconsistent.
Review the configured LLM gateway before installing. Use only trusted HTTPS or loopback endpoints, restrict and rotate OPENCLAW_GATEWAY_TOKEN, assume monitored Telegram message text can leave the host for summarization, and avoid monitoring sensitive channels unless that external processing is acceptable.
src/index.js:38Gateway Credential Disclosure Through an Unvalidated Gateway URL
src/summarizer.js:65Indirect Prompt Injection Through Untrusted Telegram Messages
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
openclaw logs --grep "tg-news" --tail 50
### Reset State (Start Fresh)
```bash
# Backup then delete state
mv ~/.openclaw/skills/tg-news-digest-lite/state/seen_messages.json \
The skill description says it extracts Telegram messages, generates AI summaries, and uses external AI endpoints, but it does not warn users that channel content may be transmitted to third-party providers such as OpenAI, OpenRouter, or DeepInfra. This omission is dangerous because users may reasonably assume scraping public channels is local processing, while the actual design can export message content to external processors with separate retention and privacy practices.
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
async clearChannel(channel) {
const state = await this.init();
if (state.channels?.[channel]) {
delete state.channels[channel];
await fs.outputJson(this.path, state, { spaces: 2 });
}
}
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
async clearChannel(channel) {
const state = await this.init();
if (state.channels?.[channel]) {
delete state.channels[channel];
await fs.outputJson(this.path, state, { spaces: 2 });
}
}
The documentation is internally inconsistent: it claims the skill does not forward raw messages to third parties, yet elsewhere states that message text is sent to an external LLM provider. This can mislead operators about privacy boundaries and cause unintended disclosure of scraped Telegram content to external services.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
openclaw config get agents.defaults.model.primary
# Test LLM connectivity manually
curl -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"qwen/qwen3.5-35b","messages":[{"role":"user","content":"test"}]}' \
https://your-gateway/v1/chat/completions
The skill exposes filesystem access to ./state and ./config.yaml and includes tools that modify tracked channels, but the description does not warn that these changes persist across runs. This is risky because users may treat tool actions as ephemeral, when they can actually alter future monitoring, cached message state, and downstream notifications.
The run_digest_cycle tool description is broad and action-oriented, which can increase the chance that an agent invokes it when a user only asks for information about monitoring or summaries. Because the tool performs network fetching, AI summarization, and delivery to a configured channel, unintended activation could trigger external data transmission and side effects without sufficiently explicit user intent.
The configure_channels description allows adding or removing monitored channels without stating authorization or scope constraints, which raises the risk of accidental or overly broad persistent reconfiguration. In context, this changes future monitoring behavior and can silently expand what content is scraped and later transmitted to external services.
The code sends raw Telegram message contents to an external LLM endpoint for summarization, which creates a real data exposure risk if messages contain sensitive, private, or regulated information. Even if this is intended functionality, there is no evidence here of user consent, redaction, minimization, or disclosure, so channel content may be transmitted off-platform without adequate safeguards.
The dependency uses a caret range, which allows newer semver-compatible releases to be installed over time instead of a single vetted version. This creates supply-chain uncertainty and can accidentally introduce vulnerable or breaking transitive code, especially for a network-facing scraping agent that depends on HTTP functionality.
"author": "your-name <your-email@example.com>",
"license": "MIT",
"dependencies": {
"axios": "^1.6.8",
"cheerio": "^1.0.0-rc.12",
"fs-extra": "^11.2.0",
"openai": "^4.28.0",
Axios is both unpinned and associated with multiple known advisories, so the manifest does not provide enough assurance that installs will avoid affected versions. Given this skill performs web scraping over the network, any SSRF, proxy-bypass, or request-manipulation flaw in the HTTP client is more relevant than it would be in an offline-only tool.
Using an unpinned fs-extra version permits automatic uptake of later compatible releases that have not been explicitly reviewed. While this is not an immediate exploit by itself, it increases supply-chain risk and reduces build reproducibility.
"dependencies": {
"axios": "^1.6.8",
"cheerio": "^1.0.0-rc.12",
"fs-extra": "^11.2.0",
"openai": "^4.28.0",
"yaml": "^2.4.1"
},
The openai package is unpinned, so future installs may resolve to a different library release than the one originally tested. In an autonomous agent context, SDK changes can affect request handling, authentication flows, or data exposure behavior, making dependency drift more consequential than in a static utility.
"axios": "^1.6.8",
"cheerio": "^1.0.0-rc.12",
"fs-extra": "^11.2.0",
"openai": "^4.28.0",
"yaml": "^2.4.1"
},
"engines": {
The yaml dependency is not pinned, and this package family has had denial-of-service style parsing issues in the past. Allowing version drift in a parser library is risky because even semver-compatible updates may expose the agent to unstable or vulnerable parsing behavior when handling untrusted content or configuration.
"cheerio": "^1.0.0-rc.12",
"fs-extra": "^11.2.0",
"openai": "^4.28.0",
"yaml": "^2.4.1"
},
"engines": {
"node": ">=20.0.0"
The yaml package has known advisories and the manifest leaves the exact installed version undefined, so vulnerable releases cannot be ruled out. If the skill parses YAML from configuration or other external sources, parser crashes or resource exhaustion could be triggered by maliciously crafted input.
The digest header uses toLocaleString('en-US', ...) directly, which forces a specific locale in user-facing output. The policy requires offering language/locale choice or clearly documenting a justified regional constraint, neither of which is present here.
The code path for cfg.group_by === "time" is commented as a placeholder for time sorting, yet it actually sorts items by channel.localeCompare, which is not time-based grouping. This is an active contradiction between inline documentation and behavior, even though the impact is limited to output formatting rather than a security-sensitive action.
The natural-language instruction mandates summary in ${config.language}, which can enforce a specific language/locale in generated output. In this file there is no indication that the user is offered a language choice or has opted into that locale behavior, which may violate language/locale policy requirements.
No suspicious patterns detected.