Back to skill

Security audit

Market Morning Brief

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly behaves like a market briefing tool, but it can silently send sensitive portfolio briefs to a configured webhook even when dry-run says it will not send anything.

Review this before installing if you will use real trading credentials or portfolio data. Do not set OPENCLAW_SLACK_WEBHOOK or slack_webhook_url unless you intend the full brief, including P&L and signals, to leave your machine; treat dry-run as unreliable for preventing webhook delivery or history writes in this version. Use least-privilege API keys where possible and avoid broad stack installs unless you want those additional trading tools.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/morning_brief.py:738
Finding

Morning dry-run mode still transmits sensitive portfolio data to a configurable webhook

Content
View full analysis
None: """Send notification via Slack webhook. Silent on failure.""" webhook_url = os.environ.get("OPENCLAW_SLACK_WEBHOOK", "") if not webhook_url: try: config = load_config() webhook_url = config.get("slack_webhook_url", "") except Exception: pass if not webhook_url: return try: data = json.dumps({"text": message}).encode("utf-8") req = urllib.request.Request(webhook_url, data=data, headers={"Content-Type": "application/json"}) urllib.request.urlopen(req, timeout=10) except Exception: pass ``` ```python parser.add_argument("--dry-run", action="store_true", help="Don't send, just print") parser.add_argument("--debug", action="store_true", help="Enable debug logging") parser.add_argument("--test-slack", action="store_true", help="Send a test Slack notification and exit") ``` ```python brief = build_morning_brief(config, kalshi, debug=args.debug) print(brief) # Send to Slack if configured _notify_slack(brief) ``` ### Technical Analysis The command-line interface explicitly states that `--dry-run` will not send the generated briefing. However, `args.dry_run` is never evaluated before `_notify_slack(brief)` is called. Consequently, all executions—including dry runs—send the complete briefing whenever `OPENCLAW_SLACK_WEBHOOK` is present. The transmitted message can contain sensitive financial information, including: - Kalshi positions and market exposure - Position quantities - Cost basis - Unrealized profit and loss - Trading signals and inferred strategy - Cross-platform market opportunities The webhook URL is taken directly from an environment variable and passed to `urllib.req ...[truncated 1785 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/evening_brief.py:373
Finding

Untrusted news content is inserted directly into local LLM instruction prompts

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/evening_brief.py:671
Finding

Evening news dry-run mode modifies persistent history despite promising no side effects

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (28)

Tainted flow: 'req' from os.environ.get (line 208, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The Slack webhook URL is taken from environment/config and used directly as an outbound request target without validation. Because the generated brief can include portfolio positions, P&L, market signals, and other sensitive trading data, a malicious or misconfigured webhook can exfiltrate that data to an attacker-controlled endpoint with no warning to the user.

Content

Scanner excerpt · scripts/morning_brief.py (reported line 209)May include surrounding context.

python
try:
        data = json.dumps({"text": message}).encode("utf-8")
        req = urllib.request.Request(webhook_url, data=data, headers={"Content-Type": "application/json"})
        urllib.request.urlopen(req, timeout=10)
    except Exception:
        pass

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The code substantially matches the declared evening-brief/news-digest concept, including the two-stage Qwen materiality gate and optional Kalshi/Xpulse-related sections. However, the declared purpose describes a broader skill whose core offering includes both morning and evening digests, with morning coverage of Kalshi P&L, Polymarket trends, and crypto prices. This code chunk only implements the evening side and contains no Polymarket or crypto-price functionality. That is a material description-to-behavior gap for this supplied code chunk. Additionally, the script uses local file persistence for news history and external subprocess calls to Ollama/Qwen, which are meaningful operational behaviors not reflected in the empty declared permissions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a user-facing prediction-market intelligence digest with financial/news aggregation and optional integrations. The actual code chunk does none of that. It is a low-level helper module for parsing JSON from Qwen/Ollama responses. While such a utility could support an AI-filtering pipeline, this code by itself does not implement the described digest functionality, data retrieval, summarization, trigger behavior, or platform integrations. This is a material description-behavior mismatch, not merely an implementation detail, because the primary purpose of the provided code chunk is unrelated to the declared end-user skill behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code substantially matches the morning-digest portion of the description: it builds a trader-focused morning brief with portfolio P&L, Polymarket markets, crypto prices, and optional sections from Kalshalyst/Arbiter/Xpulse caches. However, there are material mismatches. First, the declared description presents a broader dual-mode product with both morning and evening briefs, including AI-filtered news and a two-stage Qwen materiality gate; none of that evening/AI behavior appears in this code chunk. Second, the code sends outbound Slack notifications automatically when a webhook is configured and supports a Slack test mode, which is a meaningful capability not disclosed in the description. Third, the declared permissions are empty, while the code performs multiple network operations and reads local config/cache files. Even if some of those are supporting details, Slack notification is a user-visible undeclared capability and the missing evening/Qwen functionality makes the description not fully accurate for this code chunk.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
87% confidence
Finding

The documentation recommends a raw shell deletion command (rm ~/.openclaw/state/evening_news_history.json) as a troubleshooting step. In agent-assisted or copy-paste workflows, encouraging direct shell execution for destructive actions can lead to accidental file deletion, path expansion mistakes, or normalization of unsafe command execution patterns.

Content

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

md
**Evening news empty:** Check Ollama is running (`ollama list`), test Qwen (`ollama run qwen3:latest "test"`), and verify ddgs (`python -c "from ddgs import DDGS; print('OK')"`).

**Stage 2 drops everything:** The materiality gate filters out non-novel news. Clear history with `rm ~/.openclaw/state/evening_news_history.json` and retry, or disable with `--no-materiality-gate`.

**Qwen timeout:** Reduce article count with `--max-per-topic 2` or skip Stage 2 with `--no-materiality-gate`.

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

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

Disable Stage 2, see Stage 1 output

python scripts/evening_brief.py --mode news --no-materiality-gate --debug

Clear history to remove context (temporary debugging)

rm ~/.openclaw/state/evening_news_history.json python scripts/evening_brief.py --mode news --debug

text

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · references/evening-pipeline.md (reported line 327)May include surrounding context.

Disable Stage 2, see Stage 1 output

python scripts/evening_brief.py --mode news --no-materiality-gate --debug

Clear history to remove context (temporary debugging)

rm ~/.openclaw/state/evening_news_history.json python scripts/evening_brief.py --mode news --debug

text

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
91% confidence
Finding

The document tells users to run a destructive rm command against a state file in their home directory. Even though the target path is specific and limited, encouraging raw shell deletion is risky because it normalizes destructive commands, bypasses confirmation, and can cause accidental data loss or misuse if copied, modified, or executed in the wrong context.

Content

Scanner excerpt · references/evening-pipeline.md (reported line 328)May include surrounding context.

python scripts/evening_brief.py --mode news --no-materiality-gate --debug

Clear history to remove context (temporary debugging)

rm ~/.openclaw/state/evening_news_history.json python scripts/evening_brief.py --mode news --debug

text

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/integration.md (reported line 586)May include surrounding context.

md
**Solution:**
1. Check cache file is being written by correct skill
2. Delete cache and let skill regenerate: `rm state/.kalshi_research_cache.json && openclaw skill run kalshalyst`
3. Verify skill configuration

---

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documentation describes capabilities that involve network access, shell execution, environment/config access, and file writes, but it declares no explicit tool scope or permissions boundary. In an agent ecosystem, missing permission declarations weakens least-privilege controls and can allow broader-than-expected execution if the runtime infers or grants capabilities implicitly.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · references/integration.md (reported line 577)May include surrounding context.

md
**Solution:**
1. Manually trigger the skill: `openclaw skill run kalshalyst`
2. Check skill is scheduled: `crontab -l | grep kalshalyst`
3. Check skill logs for errors

### Brief shows wrong data

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This documentation instructs the skill to use Kalshi API credentials, including a private key file, and to make live authenticated requests, but it provides no warning about secure key storage, least-privilege handling, or the fact that account portfolio data will be transmitted to an external service. In an agent-skill context, that omission is risky because users may enable the integration without understanding that sensitive financial/account data and secrets are involved.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The Coinbase section documents use of an API key for live market data retrieval without warning that a secret is required or that the skill performs external network access. Even if intended for market data, users may supply reusable API credentials that could be mishandled, logged, or over-scoped, and the documentation does not set safe expectations for secret handling.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: requests==2.32.5 — 2 advisory(ies): CVE-2026-25645 (Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility func); CVE-2026-25645 (Requests is a HTTP library. Prior to version 2.33.0, the `requests.utils.extract)

Medium
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is pinned to requests==2.32.5, and the supplied advisory indicates versions prior to 2.33.0 are affected by an insecure temporary file reuse issue in extract_zipped_paths(). Even if this helper is not commonly exercised, shipping a known-vulnerable pinned version leaves the skill exposed if any code path or transitive usage invokes the affected functionality, especially when handling attacker-influenced archive or path material.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

In news mode, the script sends configured topic strings to DuckDuckGo news search APIs via ddgs/duckduckgo_search. While network access is part of the feature, the code around these outbound requests does not provide a direct user-facing disclosure or prompt indicating that query topics will be transmitted to an external service.

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/evening_brief.py (reported line 390)May include surrounding context.

python
f"}}"
            )

            result = subprocess.run(
                ["ollama", "run", "qwen3:latest", "--format", "json", prompt],
                capture_output=True, timeout=30, text=True
            )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
75% confidence
Finding

The script passes article titles, bodies, sources, and topics to an ollama subprocess for AI analysis. Although this appears central to the news-digest feature, there is no explicit user-facing disclosure in the code that article data will be forwarded to a model process for filtering and summarization.

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/evening_brief.py (reported line 499)May include surrounding context.

python
"Respond in JSON: {\"keep\": [list of article titles to keep], \"reasoning\": \"one line explaining why\"}"
        )

        result = subprocess.run(
            ["ollama", "run", "qwen3:latest", "--format", "json", prompt],
            capture_output=True, timeout=90, text=True
        )

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/evening_brief.py (reported line 704)May include surrounding context.

python
private_key_file = config["kalshi"].get("private_key_file")

                if api_key_id and private_key_file:
                    base_url = "https://api.elections.kalshi.com/trade-api/v2"
                    sdk_config = KalshiConfiguration(host=base_url)
                    with open(private_key_file) as f:
                        sdk_config.private_key_pem = f.read()

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/morning_brief.py (reported line 758)May include surrounding context.

python
private_key_file = config["kalshi"].get("private_key_file")

                if api_key_id and private_key_file:
                    base_url = "https://api.elections.kalshi.com/trade-api/v2"
                    sdk_config = KalshiConfiguration(host=base_url)
                    with open(private_key_file) as f:
                        sdk_config.private_key_pem = f.read()

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill silently supports sending the full generated brief to Slack, but the manifest describes it as a standalone digest generator and does not clearly disclose this external transmission behavior. Hidden data egress is security-relevant here because the brief may contain account holdings, unrealized P&L, and trading signals that users may expect to remain local.

Content

No source excerpt is available for this finding.

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/morning_brief.py (reported line 560)May include surrounding context.

python
for ticker in tickers:
        try:
            url = f"https://api.coinbase.com/v2/prices/{ticker}-USD/spot"
            resp = requests.get(url, timeout=3, headers={"Authorization": f"Bearer {api_key}"})
            resp.raise_for_status()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

After printing the brief, the script automatically sends it to Slack with no user-facing confirmation in the normal execution path. In this skill's context, the transmitted content can include sensitive financial positions and strategy-relevant signals, so silent exfiltration to a third-party service increases privacy and operational risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The markdown file tells users to place Kalshi credentials in a config file to enable live P&L, but it does not include any caution that these are sensitive credentials or that doing so grants access to account-linked data. For markdown files, the rule calls for warnings when described behavior could affect privacy or sensitive data handling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The skill handles sensitive personal trading data, including portfolio positions, P&L, and potentially social-signal caches, but it does not clearly warn users about the sensitivity, retention, or exposure of that data. While not an exploit by itself, this increases the chance of accidental disclosure through logs, chat delivery, shared devices, or integrations.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.