Back to skill

Security audit

Sovereign Daily Digest

Security checks for vulnerabilities and agentic risk

Overview

This daily briefing skill appears purpose-built, but its script can collect private local data beyond the stated configuration and contains unsafe HTML-generation code that needs review before use.

Review this skill before installing. It should not be used on sensitive calendars, task files, or authenticated GitHub accounts until it enforces explicit source opt-in, fixes the Python path interpolation, escapes HTML output, and adds clear confirmations for scheduling, email sending, and archive deletion.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/digest.sh:584
Finding

Arbitrary Python Code Execution Through Output-Path Interpolation

Content
View full analysis
/dev/null } ``` `OUTPUT_DIR` can be supplied through the command line: ```bash --output) OUTPUT_DIR="$2" shift 2 ;; ``` ### Technical Analysis The `--output` argument is controlled by the caller and becomes part of `md_file` and `html_file`. These paths are then interpolated directly into the source text passed to `python3 -c`. Shell quoting around `"${OUTPUT_DIR}"` does not protect the Python source. A path containing a single quote and a valid Python expression can terminate or alter the Python string literal. When HTML generation runs, Python interprets the resulting value as source code rather than as data. For example, a malicious output path can alter an expression such as: ```python with open('${md_file}', 'r') as f: ``` so that a Python function call executes while Python evaluates the argument passed to `open()`. Execution can occur before the subsequent file operation fails. This is a source-code injection vulnerability. It is distinct from ordinary shell command injection because the affected interpreter is Python. ### Attack Path 1. An attacker gains the ability to influence arguments used to invoke `digest.sh`, including through an automation wrapper or scheduled invocation. 2. The atta ...[truncated 1119 chars]
Remediation
View remediation
/dev/null`; return a controlled diagnostic without exposing secrets. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/digest.sh:599
Finding

Stored HTML Injection Through Unescaped Digest Content

Content
View full analysis
'); in_list = False out.append(f'

{stripped[2:]}

') elif stripped.startswith('## '): if in_list: out.append(''); in_list = False out.append(f'

{stripped[3:]}

') elif stripped.startswith('### '): if in_list: out.append(''); in_list = False out.append(f'

{stripped[4:]}

') elif stripped.startswith('> '): out.append(f'
{stripped[2:]}
') elif stripped.startswith('---'): out.append('
') elif stripped.startswith('- ') or stripped.startswith('* '): if not in_list: out.append('
    '); in_list = True out.append(f'
  • {stripped[2:]}
  • ') elif stripped.startswith('|') and '|' in stripped[1:]: if '---' in stripped: continue cells = [c.strip() for c in stripped.split('|')[1:-1]] if not in_table: out.append('' + ''.join(f'' for c in cells) + '') in_table = True else: out.append('' + ''.join(f'' for c in cells) + '') elif stripped == '' and in_table: out.append('
    {c}
    {c}
    ') in_table = False elif stripped.startswith('*') and stripped.endswith('*') and not stripped.startswith('**'): out.append(f'

    {stripped[1:-1]}

    ') elif stripped: ...[truncated 2785 chars]
Remediation
View remediation
{safe_heading}") ``` 2. Escape table cells, list entries, headings, blockquotes, task text, event summaries, feed titles, descriptions, and quote content. 3. Parse links separately and allow only approved schemes such as `https` and, if necessary, `http`. 4. Reject `javascript:`, `data:`, `file:`, and other unexpected schemes. 5. Escape attribute values with `quote=True`. 6. Add `rel="noopener noreferrer"` to links using `target="_blank"`. 7. Do not sanitize HTML with regular expressions. 8. Consider applying a sanitizer such as Bleach after Markdown conversion with a minimal element and attribute allowlist. 9. Add tests containing script tags, event handlers, encoded payloads, malformed tags, quote characters, and dangerous URL schemes. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/digest.sh:249
Finding

Configured Source Restrictions Are Ignored During Private Data Collection

Content
View full analysis
> "$overdue_file" elif [[ "$due_date" == "$TODAY" ]]; then echo "- ${line}" >> "$today_file" else echo "- ${line}" >> "$other_file" fi else echo "- ${line}" >> "$other_file" fi done < "$todotxt_path" fi # Markdown task lists local md_tasks_path="${HOME}/tasks.md" if [[ -f "$md_tasks_path" ]]; then grep -E '^\s*- \[ \]' "$md_tasks_path" 2>/dev/null | while IFS= read -r line; do COUNT_TASKS=$((COUNT_TASKS + 1)) echo "${line}" >> "$other_file" done fi # GitHub issues (if gh CLI is available) if command -v gh &> /dev/null; then local gh_issues gh_issues=$(gh issue list --assignee @me --state open --limit 10 --json title,url,updatedAt 2>/dev/null || echo "") if [[ -n "$gh_issues" && "$gh_issues" != "[]" ]]; then echo "$gh_issues" | python3 -c " import sys, json try: issues = json.load(sys.stdin) for i in issues: print(f\"- [ ...[truncated 2633 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

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

issing config, etc.).

  • When the next scheduled digest will run (if scheduling is enabled).

Scheduling

If the user asks to schedule the digest:

  1. Parse the desired schedule into a cron expression.
  2. Update the config file with the cron expression and schedule.enabled: true.
  3. Create a crontab entry (Linux/macOS) or a scheduled task (Windows):
bash
# Linux/macOS
(crontab -l 2>/dev/null; echo "${CRON} cd ~/.openclaw/daily-digest && bash scripts/digest.sh") | crontab -

# Windows (PowerShell)
# Provide instructions for Task Scheduler
  1. Confirm the schedule to the user.

Edge Cases and Error Handling

  • No internet: Skip weather, RSS, and email. Generate digest from local sources only. Add a banner: "Generated in offline mode — some sections may be incomplete."
  • Empty sections: Omit sections that have zero items rather than showing empty tables.
  • Large feeds: Never process more than 50 items per feed. Truncate g

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The usage examples use generic activation phrases like "Give me my daily digest" and "Morning briefing with just calendar and tasks" without any explicit invocation constraints, exclusion conditions, or clarification about when this skill should activate. In a skill catalog or agent environment, these phrases are broad enough to collide with everyday requests for summaries or planning assistance.

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 · README.md (reported line 247)May include surrounding context.

bash
# Edit crontab
crontab -e

# Add this line for 7:00 AM every day
0 7 * * * cd ~/.openclaw/skills/daily-digest && bash scripts/digest.sh --format both

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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 · README.md (reported line 255)May include surrounding context.

md
### macOS (launchd)

Create `~/Library/LaunchAgents/com.openclaw.daily-digest.plist` with the appropriate schedule.

### Windows (Task Scheduler)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill advertises broad trigger phrases such as 'daily report' and 'summarize my day' that can overlap with ordinary user requests, increasing the chance of unintended invocation. In a skill that reads local files, fetches network resources, writes output, and may alter scheduling, accidental activation can expose personal data or cause side effects without clear user intent.

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 123)May include surrounding context.

md
### Step 1: Load Configuration

1. Read `~/.openclaw/daily-digest/config.yaml`.
2. If the file is missing, create it with the defaults above, then inform the user: "I created a default config at `~/.openclaw/daily-digest/config.yaml`. Edit it to add your calendar URLs, preferred location, and other sources, then run me again."
3. Validate all fields. Warn (do not crash) on missing optional fields.

### Step 2: Determine Date Context

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The data-gathering steps direct the skill to contact external services such as wttr.in, RSS feeds, zenquotes.io, GitHub, and possibly IMAP, but the description does not clearly warn users that their configured locations, feed selections, repository identifiers, and potentially other metadata will be transmitted externally. This weakens informed consent and can lead to privacy exposure during normal use.

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 304)May include surrounding context.

md
### Step 6: Save Output

1. Create the output directory if it does not exist.
2. Save the file as `{output_dir}/digest-{YYYY-MM-DD}.md` and/or `.html`.
3. If `archive` is true, keep previous files up to `max_archive_days`, deleting older ones.
4. Print the full digest to stdout as well.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The scheduling section instructs the skill to modify crontab or create scheduled tasks, which is a persistent system change, but it does not require a strong warning or explicit confirmation. Because this establishes recurring execution of a script that reads local data and performs network activity, users may unknowingly authorize long-lived automated behavior.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

This line installs a cron entry that repeatedly executes a local script, creating persistence on the host. While scheduling is an expected feature for a digest tool, persistence is still security-relevant because it causes recurring execution with access to local files, network endpoints, and potentially sensitive personal data.

Content

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

bash
# Linux/macOS
(crontab -l 2>/dev/null; echo "${CRON} cd ~/.openclaw/daily-digest && bash scripts/digest.sh") | crontab -

# Windows (PowerShell)
# Provide instructions for Task Scheduler

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The follow-up action 'Send this to [email]' enables transmission of digest contents to an external recipient without an accompanying warning that the digest may contain sensitive calendar, task, email, or news-derived information. This creates a realistic risk of accidental data exfiltration through user-friendly workflow text.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script makes automatic outbound requests to third-party services such as wttr.in, hnrss.org, TechCrunch, and zenquotes without explicit consent or clear disclosure. Even if the payload is small, it transmits user-linked metadata such as IP address and, for weather, user-supplied location, creating privacy risk in a personal-assistant context.

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 · scripts/digest.sh (reported line 107)May include surrounding context.

sh
log "Config not found. Creating default at $CONFIG_FILE"
        mkdir -p "$(dirname "$CONFIG_FILE")"
        cp "${SKILL_DIR}/SKILL.md" /dev/null 2>/dev/null || true
        # Write a minimal default config
        cat > "$CONFIG_FILE" << 'YAML'
general:
  timezone: "America/New_York"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script reads sensitive local data sources including calendars, task files, and GitHub-assigned issues, then writes aggregated contents into persistent digest files. In a daily-digest skill, this can expose private schedules, tasks, and work items to other local users, backups, sync services, or downstream consumers of the generated output.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

At L350 the user-facing message says task sources are configured via the config, implying task inputs come from configuration. However, the actual implementation in fetch_tasks reads only hard-coded paths like ~/todo.txt and ~/tasks.md and optionally queries GitHub issues, with no code that parses configured task sources from config.yaml.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automatically deletes older digest markdown and HTML files using find -delete, which is a destructive operation. There is a log entry about cleaning archives, but no explicit warning in the help text or interface that running the script will remove prior outputs older than 30 days.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are generic productivity-language terms such as 'daily digest', 'daily report', and 'summarize my day', which are likely to match normal user requests rather than explicit invocation of this specific skill. This can cause the skill to activate unexpectedly and gain access to its required tooling or downstream workflows in contexts where the user did not intend to run it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The README mentions that first run creates a default configuration file and later describes output directories and scheduled execution, but it does not clearly warn users that running the skill will create and persist files on disk. For markdown files, user-facing documentation should disclose behavior that affects local data or system state.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The default configuration sets language: "en", which establishes a specific language preference by default. The file does not indicate that the user is asked to choose a language initially or that this locale restriction is necessary for a region-specific purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.