Back to skill

Security audit

Dinstein Tech News Digest

Security checks for vulnerabilities and agentic risk

Overview

This news digest skill is not plainly malicious, but it should be reviewed because it can use credentials, fetch broad external URLs, create scheduled delivery workflows, and send reports to email or chat destinations.

Before installing, review and restrict configured sources and destinations, use least-privilege API tokens, avoid enabling GitHub credential fallbacks unless intended, and only create cron jobs or email/chat delivery after confirming where reports will be sent. Run network-fetching parts in an environment that cannot reach localhost, private networks, or cloud metadata services if untrusted feeds or custom RSS sources may be used.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Warning
Location
references/digest-prompt.md:120
Finding

Mandatory Promotional Content Injection into Generated Reports

Content
View full analysis
| | Powered by OpenClaw ``` ``` Equivalent promotional content is embedded in the output templates: ```markdown 🤖 Generated by tech-news-digest v{{version}} | | Powered by OpenClaw ``` ### Technical Analysis The controlling prompt requires the agent to append a fixed brand attribution and external project link to generated reports. The same content appears in the Discord, email, and PDF templates, making the behavior consistent across output channels. This content is not derived from the user's requested news content or delivery configuration. Because the Skill's instructions determine the report structure, users invoking the Skill receive promotional content unless they manually override or edit the bundled instructions. The behavior does not grant system privileges or execute code. Its security relevance is limited to alteration of agent output and insertion of outbound links into user-facing reports. ### Attack Path 1. A user or scheduled job directs the agent to follow `references/digest-prompt.md`. 2. The agent generates a digest using the bundled report instructions. 3. The mandatory footer is copied into the report. 4. The resulting Discord message, email, Markdown archive, or PDF contains fixed promotional attribution and an external project link. 5. Recipi ...[truncated 451 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch-rss.py:274
Finding

Server-Side Request Forgery Through Configured and Feed-Derived URLs

Content
View full analysis
str: """Resolve relative links against the feed URL. Rejects non-HTTP(S) schemes.""" if not link: return link if link.startswith(("http://", "https://")): return link resolved = urljoin(base_url, link) if not resolved.startswith(("http://", "https://")): return "" # reject javascript:, data:, etc. return resolved ``` ```python def fetch_feed_with_retry(source: Dict[str, Any], cutoff: datetime, no_cache: bool = False) -> Dict[str, Any]: """Fetch RSS feed with retry mechanism and conditional requests.""" source_id = source["id"] name = source["name"] url = source["url"] priority = source["priority"] topics = source["topics"] global _rss_cache, _rss_cache_dirty for attempt in range(RETRY_COUNT + 1): try: req_headers = {"User-Agent": "TechDigest/2.0"} # Add conditional headers from cache (thread-safe) with _rss_cache_lock: cache = _rss_cache if _rss_cache is not None else {} cache_entry = cache.get(url) now = time.time() ttl_seconds = RSS_CACHE_TTL_HOURS * 3600 if cache_entry and not no_cache and (now - cache_entry.get("ts", 0)) < ttl_seconds: if cache_entry.get("etag"): req_headers["If-None-Match"] = cache_entry["etag"] if cache_entry.get("last_modified"): req_headers["If-Modified-Since"] = cache_entry["last_modified"] req = Req ...[truncated 3213 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send-email.py:54
Finding

Mailer Option Injection Through Unvalidated Recipient Arguments

Content
View full analysis
bool: """Send via msmtp (preferred).""" try: result = subprocess.run( ['msmtp', '--read-envelope-from'] + to_addrs, input=message.encode('utf-8'), stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30 ) if result.returncode == 0: return True logging.error(f"msmtp failed: {result.stderr.decode()}") return False except FileNotFoundError: logging.debug("msmtp not found") return False except Exception as e: logging.error(f"msmtp error: {e}") return False def send_via_sendmail(message: str, to_addrs: list) -> bool: """Send via sendmail (fallback).""" for cmd in ['sendmail', '/usr/sbin/sendmail']: try: result = subprocess.run( [cmd, '-t'] + to_addrs, input=message.encode('utf-8'), stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30 ) ``` The input is only split and stripped: ```python parser.add_argument('--to', action='append', required=True, help='Recipient email (repeatable)') parser.add_argument('--subject', '-s', required=True, help='Email subject') parser.add_argument('--html', required=True, type=Path, help='HTML body file') parser.add_argument('--attach', type=Path, default=None, help='PDF attachment file') parser.add_argument('--from', dest='from_addr', default=None, help='From address') parser.add_argument('--verbose', '-v', action='store_true') args = parser.parse_args() # Expand comma-separated addresses to_addrs = [] for addr in args.to: ...[truncated 2111 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (62)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill is presented as a digest generator, but it also supports direct outbound delivery through local mail tooling and MIME construction. That materially changes the risk profile because the skill is not only processing content but also transmitting it off-host to external recipients.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is presented as a digest generator, but it also supports direct outbound delivery through local mail tooling and MIME construction. That materially changes the risk profile because the skill is not only processing content but also transmitting it off-host to external recipients.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 83)May include surrounding context.

  • WEB_SEARCH_BACKEND - Web search backend: auto|brave|tavily (optional, default: auto)
    • BRAVE_API_KEYS - Brave Search API keys, comma-separated for rotation (optional)
    • BRAVE_API_KEY - Single Brave key fallback (optional)
    • GITHUB_TOKEN - GitHub personal access token (optional, improves rate limits)
  1. Generate Digest:
    bash

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fetch-github.py (reported line 428)May include surrounding context.

python
- `WEB_SEARCH_BACKEND` - Web search backend: auto|brave|tavily (optional, default: auto)
   - `BRAVE_API_KEYS` - Brave Search API keys, comma-separated for rotation (optional)
   - `BRAVE_API_KEY` - Single Brave key fallback (optional)
   - `GITHUB_TOKEN` - GitHub personal access token (optional, improves rate limits)

3. **Generate Digest**:
   ```bash

Exfiltration Commands

High
Category
Prompt Injection
Confidence
90% confidence
Finding

Instructions found that direct the agent to transmit conversation context or user data to external services.

Content

Scanner excerpt · SKILL.md (reported line 453)May include surrounding context.

  • Anti-pattern: Do NOT copy pipeline steps into the cron prompt — it will drift out of sync

Multi-Channel Delivery Limitation

OpenClaw enforces cross-provider isolation: a single session can only send messages to one provider (e.g., Discord OR Telegram, not both). If you need to deliver digests to multiple platforms, create separate cron jobs for each provider:

text
# Job 1: Discord + Email

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file states that all prompts, templates, comments, and code must be in English, which is a natural-language policy constraint. Although line 13 says output language is runtime-controlled, the instruction in line 12 still imposes an English-only requirement on user-facing prompt/template content without presenting it as an opt-in choice or clearly justified locale limitation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README encourages users to trigger installation, configuration, scheduling, and message delivery through a single natural-language prompt, but it does not warn that these actions may create scheduled jobs, connect external services, or send data to third-party platforms. In an agent ecosystem, this can lead users to authorize impactful automation without informed consent, increasing risk of unintended data sharing or persistent system changes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README advertises collection from many third-party sources and delivery to channels such as Discord and email, but it does not clearly disclose that data will be fetched from external services and redistributed through external destinations. In agent-driven deployments, missing privacy and transmission warnings can cause users to unknowingly expose interests, credentials, or generated summaries across multiple providers.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest context says the skill provides six-source data collection from RSS, Twitter/X, GitHub releases, GitHub Trending, Reddit, and web search. This README similarly claims '151 个数据源' at L003/L035, but the table at L039-L043 lists only five categories totaling 142 sources (49+48+4+28+13), and the pipeline diagram at L050-L054 also shows only five collectors. That is a semantic mismatch in what the skill claims to cover versus what the documentation describes it actually doing.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill documents significant capabilities including shell execution, outbound network access, environment-variable credential use, and file read/write, but it does not declare an explicit tool scope or permissions boundary. In an agent setting, this weakens policy enforcement and makes it easier for the skill to exercise broader powers than a reviewer might expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The daily cron example sets LANGUAGE = English as a fixed instruction. This is a natural-language locale constraint presented without any opt-in or alternative language choice, which can violate language policy requirements for user-selectable locale behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The weekly cron example also fixes LANGUAGE = English rather than offering a user choice. Because the file otherwise describes a general-purpose digest tool rather than a clearly English-only regional/compliance use case, this appears to be an avoidable language-policy issue.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · SKILL.md (reported line 453)May include surrounding context.

  • Anti-pattern: Do NOT copy pipeline steps into the cron prompt — it will drift out of sync

Multi-Channel Delivery Limitation

OpenClaw enforces cross-provider isolation: a single session can only send messages to one provider (e.g., Discord OR Telegram, not both). If you need to deliver digests to multiple platforms, create separate cron jobs for each provider:

text
# Job 1: Discord + Email

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The network-access section claims data is only sent to a fixed set of endpoints, but elsewhere the skill describes fetching full text from arbitrary article URLs and using agent web-search fallback. This inconsistency obscures the real egress surface and undermines security review of external communications.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The security notes state that no files outside the workspace are accessed, yet the documented GitHub App flow reads a private key from an arbitrary path via GH_APP_KEY_FILE. This kind of inaccurate assurance can cause reviewers to approve a skill under false assumptions about filesystem access.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes a tech news digest skill focused on six-source collection for tech-oriented topics, but this configuration includes a substantial separate 'crypto' topic taxonomy across RSS, Twitter/X, GitHub, and Reddit sources. That broadens the skill from technology news aggregation into cryptocurrency-specific monitoring, which is not reflected in the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This JSON manifest enables multiple Chinese-language feeds and notes them explicitly as Chinese media, but the file does not indicate that use of non-English sources is opt-in or limited to a region-specific mode. Under the policy, forcing or silently imposing a specific language/locale without user choice is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a tech news digest centered on six collection sources and common technology domains, but this configuration adds a dedicated 'crypto' section covering Bitcoin, Ethereum, DeFi, NFTs, and market developments. That is a meaningful expansion of subject matter into cryptocurrency/news-finance content rather than an obvious implementation detail of a general tech digest.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The placeholder default sets the report language to Chinese, and the instruction later requires writing the report in . There is no opt-in, user choice flow, or documented justification that this skill is intended only for a Chinese-language context, which creates a locale policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The prompt instructs deletion of archive files older than 90 days without requiring explicit user confirmation, warning, or safety checks on the target path. In an agentic context where is substituted dynamically, this creates a real risk of unintended data loss if the workspace is misconfigured or broader than expected.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This instruction requires the generated report to be written in the configured language, while elsewhere the default language is fixed to Chinese. Because the file does not provide an explicit user language choice or justified region-specific limitation, it constitutes a natural-language locale policy violation.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest describes a tech news digest pipeline that collects from GitHub releases and trending data, but this file also shells out to external binaries to sign JWTs and retrieve auth tokens. Spawning subprocesses for credential generation and token harvesting is not an obvious requirement of a content-fetching skill and introduces a materially different capability.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/fetch-github.py (reported line 65)May include surrounding context.

python
f.write(private_key)
        tmp_key = f.name
    try:
        result = _sp.run(
            ['openssl', 'dgst', '-sha256', '-sign', tmp_key],
            input=signing_input.encode(), stdout=_sp.PIPE, stderr=_sp.PIPE, universal_newlines=False, timeout=10,
        )

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch-github.py (reported line 80)May include surrounding context.

python
# Exchange JWT for installation token
    req = Request(
        f"https://api.github.com/app/installations/{install_id}/access_tokens",
        method='POST',
        headers={
            'Authorization': f'Bearer {jwt}',

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fetch-github.py (reported line 265)May include surrounding context.

python
# Exchange JWT for installation token
    req = Request(
        f"https://api.github.com/app/installations/{install_id}/access_tokens",
        method='POST',
        headers={
            'Authorization': f'Bearer {jwt}',

Static analysis

No suspicious patterns detected.