Back to skill

Security audit

Daily Brief Digest

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real daily-digest helper, but it handles private email and calendar data, stores full reports permanently, and encourages recurring automated runs without enough containment or retention controls.

Install only if you are comfortable with the skill reading local email and calendar data, creating permanent local digest archives, and optionally sending summaries through your configured messaging channel. Review or disable the cron setup unless you want unattended daily runs, and consider modifying the script to escape HTML, restrict file permissions, redact sensitive fields, and add retention or opt-out controls.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/digest.js:13
Finding
Persistent Plaintext Storage of Sensitive Personal Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/digest.js:13-14`, `scripts/digest.js:102-106` **Vulnerability Type**: Sensitive data stored persistently without adequate access controls **Risk Level**: Medium ### Vulnerable Code ```javascript const dateStr = new Date().toISOString().split('T')[0]; const logDir = path.join(process.env.USERPROFILE || process.env.HOME, '.openclaw', 'cron', 'DailyDigest_logs'); const logFile = path.join(logDir, `${dateStr}.md`); ``` ```javascript try { if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true }); fs.writeFileSync(logFile, markdownContent); console.log(`Successfully logged digest to: ${logFile}`); ``` The behavior is also explicitly described in `SKILL.md:14-20`: ```markdown 4. **Log & Present**: Use `scripts/digest.js` to assemble these components into a stylized HTML report. **CRITICAL: The script automatically saves this report as a permanent Markdown file in `.openclaw/cron/DailyDigest_logs/[date].md` for historical record.** 5. **Notify User**: Send a brief notification via the `message` tool to the user's active channel. Mention that the full detailed log is available at `.openclaw/cron/DailyDigest_logs/[date].md`. ## Data Sources - **Email**: `himalaya` CLI. - **Calendar**: `gog` CLI. - **News**: Web search or trusted RSS feeds. - **Logs**: Saved locally to `~/.openclaw/cron/DailyDigest_logs/`. ``` ### Technical Analysis The generated report contains email senders and subjects, calendar entries, tasks, and news data. The script writes the complete report to a predictable, persistent Markdown file under the user's home directory. Neither `fs.mkdirSync` nor `fs.writeFileSync` specifies an explicit restrictive filesystem mode. Access therefore depends on the process umask, existing directory permissions, and platform defaults. The implementation also has no retention policy, field-level redaction, encryption, or opt-out control. Reports accumulate by date and may co ...[truncated 1687 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make historical logging explicitly opt-in rather than mandatory. 2. Create the storage directory with owner-only permissions: ```javascript fs.mkdirSync(logDir, { recursive: true, mode: 0o700 }); ``` 3. Write reports with an explicit owner-only mode: ```javascript fs.writeFileSync(logFile, markdownContent, { encoding: 'utf8', mode: 0o600 }); ``` 4. Check and correct permissions when the directory or destination file already exists. 5. Redact or omit sensitive fields by default, particularly email addresses, subjects, calendar descriptions, and task details. 6. Add a configurable retention period and securely remove reports after expiration. 7. Offer a non-persistent mode that returns the digest without writing it to disk. 8. Clearly notify the user before enabling scheduled permanent storage. 9. Avoid placing these reports in directories synchronized to cloud storage unless the user explicitly requests it. 10. If long-term archives are required, encrypt them using a key managed separately from the report directory. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/digest.js:42
Finding
Stored HTML Injection Through Unescaped Digest Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/digest.js:42-92` **Vulnerability Type**: Stored HTML injection and unsafe URL rendering **Risk Level**: Medium ### Vulnerable Code ```javascript ${emails.length > 0 ? emails.map(e => ` <div style="padding: 12px; border-radius: 8px; background: #f8fafc; margin-bottom: 10px; border-left: 4px solid #0077b5;"> <div style="font-weight: bold; color: #1e293b;">${e.subject}</div> <div style="font-size: 0.9em; color: #64748b;">From: ${e.from.name || e.from.addr} • ${new Date(e.date).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</div> </div> `).join('') : '<p style="color: #94a3b8; font-style: italic;">No urgent emails found.</p>'} ``` ```javascript ${calendar.length > 0 ? calendar.map(c => ` <div style="padding: 12px; border-radius: 8px; background: #fdf2f2; margin-bottom: 10px; border-left: 4px solid #ef4444;"> <div style="font-weight: bold; color: #991b1b;">${c.summary}</div> <div style="font-size: 0.9em; color: #b91c1c;">${c.start} - ${c.end}</div> </div> `).join('') : '<p style="color: #94a3b8; font-style: italic;">Your schedule is clear today.</p>'} ``` ```javascript ${tasks.length > 0 ? tasks.map(t => ` <div style="padding: 12px; border-radius: 8px; background: #f0fdf4; margin-bottom: 10px; border-left: 4px solid #22c55e;"> <div style="font-weight: bold; color: #166534;">${t.title}</div> ${t.due ? `<div style="font-size: 0.9em; color: #15803d;">Due: ${t.due}</div>` : ''} </div> `).join('') : '<p style="color: #94a3b8; font-style: italic;">No tasks due today.</p>'} ``` ```javascript ${news.length > 0 ? news.map(n => ` <div style="margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px dashed #e2e8f0;"> <a href="${n.url}" style="text-decoration: none; font-weight: 600; color: #1e293b; display: block; margin-bottom: 4px; font-size: 1.1em;">${n.title}</a> <p style="margin: 0; font-size: 0.9e ...[truncated 2999 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply HTML encoding to every value inserted into an HTML text context: ```javascript function escapeHtml(value) { return String(value ?? '') .replaceAll('&', '&amp;') .replaceAll('<', '&lt;') .replaceAll('>', '&gt;') .replaceAll('"', '&quot;') .replaceAll("'", '&#39;'); } ``` 2. Use `escapeHtml` for subjects, names, addresses, event data, task data, titles, and snippets. 3. Validate URLs separately rather than relying only on HTML encoding: ```javascript function safeHttpUrl(value) { try { const url = new URL(String(value)); return ['https:', 'http:'].includes(url.protocol) ? url.href : '#'; } catch { return '#'; } } ``` 4. Encode the validated URL before placing it into the `href` attribute. 5. Reject dangerous or unnecessary schemes, including `javascript:`, `data:`, `file:`, and custom application protocols. 6. Validate the complete input structure and require expected primitive types before rendering. 7. Prefer a maintained templating system with automatic contextual escaping. 8. If raw HTML is not required, generate ordinary Markdown text and escape Markdown control characters. 9. If HTML output remains necessary, sanitize the completed document with a well-reviewed allowlist sanitizer. 10. Ensure the viewing environment disables scripts, event-handler attributes, embedded frames, forms, and unauthorized external resources. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared purpose says the skill generates a daily brief, but the workflow also persists the report to disk, may inspect tasks/contacts, and sends a notification, all of which materially expand its behavior beyond a simple summary. This mismatch undermines informed consent and can expose sensitive personal data by causing users or orchestrators to invoke the skill without realizing it performs retention and broader data collection.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill invokes local capabilities and sensitive data sources (`himalaya`, `gog`, and implied environment/local tooling) without declaring an explicit tool or permission scope. That makes the skill's effective privileges opaque to users and reviewers, increasing the chance of overbroad access to email/calendar data or unsafe execution in a more privileged runtime than expected.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The workflow goes beyond generating a brief by automatically saving a permanent historical log and sending a message notification. Those side effects create privacy and retention risks because personal email and calendar content may be stored and broadcast even when the user only asked for a transient morning summary.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The invocation phrases are broad enough that ordinary requests for a 'status update' or similar wording could trigger the skill in contexts where the user did not intend email/calendar/news aggregation. Because this skill accesses sensitive personal data and performs side effects, unintended activation increases the chance of unnecessary data access and logging.

Ssd 3

Medium
Confidence
97% confidence
Finding
The skill explicitly instructs the agent to create permanent local records containing content derived from personal emails and calendar events, then direct the user to those logs. Persistent storage of sensitive communications and schedule data creates a substantial privacy risk, expands the blast radius of compromise, and may violate data-minimization expectations for a simple daily digest.

Session Persistence

Medium
Category
Rogue Agent
Content
# Setting Up the Daily Digest Cron Job

To have your digest generated automatically every morning, add a cron job to OpenClaw.

## Example Cron Command
Confidence
88% confidence
Finding
The document instructs users to create a persistent cron job that will automatically run the skill every morning, causing repeated access to email, calendar, and news sources without a fresh user action each time. Persistent automation is risky here because the task handles private communications and can also log and forward results, so any over-collection, prompt injection, or misconfiguration becomes a recurring issue.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The guide explicitly states that the automated digest will access private emails and then send a summary through external messaging channels, but it does not warn the user about the privacy implications or encourage limiting sensitive content. In a recurring cron context, this increases the chance that confidential information is routinely exfiltrated to third-party channels or exposed on less secure devices.

Context-Inappropriate Capability

Medium
Confidence
78% confidence
Finding
A daily briefing skill is expected to summarize provided email/calendar/news data, but this implementation shells out to an external program via execSync to fetch mail directly. That subprocess execution capability is more powerful than the manifest’s stated purpose and is not mentioned as part of the skill’s scope.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script collects personal email data and combines it with calendar items, tasks, and news, then stores the resulting digest on disk without any visible consent, notice, or data-minimization controls. Even if intended for convenience, silent collection and retention of sensitive personal data creates a meaningful privacy and security risk in a personal-assistant context.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script writes the full daily digest, including email subjects/senders, calendar events, and tasks, to a persistent file under the user's home directory. This creates unnecessary local retention of sensitive personal data beyond the stated briefing function, increasing exposure to other local users, backups, endpoint compromise, or later unintended reuse.

Description-Behavior Mismatch

Low
Confidence
92% confidence
Finding
The manifest scope names urgent emails, upcoming calendar events, and relevant news as the components of the daily brief. The code also accepts and renders a separate tasks section, extending behavior beyond the described data sources.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The call to toLocaleDateString explicitly hard-codes 'en-US', which imposes a specific language/locale format regardless of the user's preferences. This matches the policy-violation category for locale constraints because there is no opt-in, configurability, or documented region-specific justification in the file.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/digest.js:20