Back to skill

Security audit

AI Daily Brief XHS

Security checks for vulnerabilities and agentic risk

Overview

The skill's AI news brief purpose is clear, but it depends on running an unaudited external local script and can be scheduled to push briefs automatically.

Review this skill before installing. It is not evidently malicious, but it should only be used where you trust the local tavily-search skill at the hardcoded path, understand that external search providers receive the news queries, and are comfortable with scheduled Feishu-style brief delivery. Prefer a version that bundles or pins the search dependency and writes output to a safer private location.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T08 · Insecure Dependencies

Warning
Location
scripts/daily-brief.mjs:10
Finding

Execution of an Unpinned External Script Dependency

Content
View full analysis

Vulnerability Details

File Location: scripts/daily-brief.mjs:10-29 and scripts/search-tavily.mjs:11-30
Vulnerability Type: Unverified external executable dependency
Risk Level: Medium

Vulnerable Code

From scripts/daily-brief.mjs:

js
// Tavily script absolute path
const TAVILY_SCRIPT = '/home/admin/.openclaw/workspace/skills/tavily-search/scripts/search.mjs';

// Search query templates
const queries = {
  companies: "OpenAI OR Google AI OR Microsoft AI OR Meta AI OR Anthropic OR DeepMind news yesterday",
  leaders: "Sam Altman OR Satya Nadella OR Sundar Pichai OR Mark Zuckerberg OR Dario Amodei AI statement yesterday",
  products: "LLM OR AI Agent OR AI Skills OR RAG new release launch product announcement yesterday",
  papers: "arXiv cs.CL cs.LG cs.AI LLM Agent RAG knowledge base paper yesterday"
};

// Execute Tavily search
function searchTavily(query, count = 10, topic = 'news') {
  try {
    const cmd = `node "${TAVILY_SCRIPT}" "${query}" -n ${count} --topic ${topic}`;
    const result = execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
    return result;
  } catch (error) {
    console.error(`Tavily search failed for query: ${query}`);
    console.error(error.message);
    return null;
  }
}

The same execution pattern appears in scripts/search-tavily.mjs:

js
// Tavily script absolute path
const TAVILY_SCRIPT = '/home/admin/.openclaw/workspace/skills/tavily-search/scripts/search.mjs';

// Execute Tavily search
function searchTavily(query, count = 10, topic = 'news') {
  try {
    const cmd = `node "${TAVILY_SCRIPT}" "${query}" -n ${count} --topic ${topic}`;
    const result = execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
    return result; // Return raw markdown output
  } catch (error) {
    console.error(`Tavily search failed for query: ${query}`);
    console.error(error.message);
    return null;
...[truncated 2277 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the external script invocation with direct Tavily API calls from audited project code.
  2. If a reusable dependency is required, package it through a lockfile-based dependency manager and pin an exact version.
  3. Verify the dependency's cryptographic hash or signature before execution when bundling is not possible.
  4. Confirm that the external file and all parent directories are owned by a trusted administrative account and are not writable by less-privileged users.
  5. Remove the machine-specific absolute path and use an explicitly configured, validated dependency location.
  6. Replace execSync() with execFileSync() or spawnSync() and pass each argument separately, avoiding shell parsing:
js
import { execFileSync } from 'node:child_process';

const result = execFileSync(
  process.execPath,
  [validatedScriptPath, query, '-n', String(count), '--topic', topic],
  {
    encoding: 'utf8',
    maxBuffer: 10 * 1024 * 1024,
    shell: false
  }
);
  1. Validate count as a bounded integer and restrict topic to an explicit allowlist even if these values later become externally configurable.
  2. Run the search component with minimal filesystem permissions and expose only the API credentials required for its operation.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/daily-brief.mjs:178
Finding

Predictable Shared Temporary File Permits Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/daily-brief.mjs:178-180
Vulnerability Type: Unsafe temporary-file handling
Risk Level: Low

Vulnerable Code

js
// Save to file
await writeFile(`/tmp/ai-daily-brief-${date.full}.md`, brief);
console.log(`\n✅ Brief saved to /tmp/ai-daily-brief-${date.full}.md`);

Technical Analysis

The script writes its report to a deterministic filename in the globally shared /tmp directory. The filename is derived only from the current date and is therefore predictable before the scheduled execution.

writeFile() follows symbolic links and opens an existing destination for truncation by default. The code does not use exclusive creation, inspect the destination with lstat(), verify ownership, create a private temporary directory, or request protections equivalent to O_NOFOLLOW.

On systems where another local user can create the expected path first, that user may place a symbolic link at the destination. When the Skill runs, the write operation can follow the link and overwrite a different file writable by the Skill account.

Attack Path

  1. A local attacker determines the date on which the daily task will execute.
  2. Before execution, the attacker creates /tmp/ai-daily-brief-YYYY-MM-DD.md as a symbolic link to another file.
  3. The scheduled or manually invoked Skill calls writeFile() on the predictable path.
  4. Node.js follows the symbolic link and truncates or replaces the linked target with the generated Markdown report.
  5. The attacker causes data loss or configuration corruption if the selected target is writable by the Skill account.

Alternatively, another local process can repeatedly replace the report file, tampering with content consumed after generation.

Impact Assessment

The maximum privilege is limited to the filesystem permissions of the account running the Skill. An attacker cannot use this flaw alone to overwrite files th ...[truncated 392 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create a process-private temporary directory with mkdtemp() and mode 0700.
  2. Create the report with exclusive semantics by setting flag: 'wx', preventing an existing path from being reused.
  3. Set restrictive file permissions such as 0600 unless broader access is explicitly required.
  4. Do not write security-sensitive output directly into a shared, predictable /tmp pathname.
  5. If a stable final filename is required, generate the report in a private directory and publish it using a carefully validated atomic operation.
  6. Verify with lstat() that an existing destination is not a symbolic link, while recognizing that exclusive atomic creation is preferable to a separate check that may introduce a time-of-check/time-of-use race.

Example hardening:

js
import { mkdtemp, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

const privateDirectory = await mkdtemp(
  join(tmpdir(), 'ai-daily-brief-')
);

const outputPath = join(privateDirectory, `${date.full}.md`);

await writeFile(outputPath, brief, {
  flag: 'wx',
  mode: 0o600
});
  1. Run the scheduled task under a dedicated, unprivileged service account to limit the impact of any filesystem-redirection issue.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manual trigger phrases are broad natural-language requests such as '昨天 AI 行业有什么大新闻' and '推送 AI 每日简报', which can easily overlap with ordinary user conversation rather than an explicit command to invoke the skill. This can cause unintended execution, especially in chat contexts where the user is casually discussing AI news, leading to surprise data fetching, noisy automation, or message pushes without clear user intent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The line '中文呈现:英文内容提供中文摘要' establishes a language requirement for the skill's output. Because the document does not offer an alternative language option or note that Chinese is user-selectable, it creates a natural-language locale policy concern.

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

使用博查 API(备用)

bash
curl -X POST "https://api.bocha.cn/v1/web-search" \
  -H "Authorization: Bearer $BOCHA_API_KEY" \
  -d '{"query":"OpenAI Google AI Microsoft AI 新闻 昨天","freshness":"day"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 · SKILL.md (reported line 106)May include surrounding context.

使用博查 API(备用)

bash
curl -X POST "https://api.bocha.cn/v1/web-search" \
  -H "Authorization: Bearer $BOCHA_API_KEY" \
  -d '{"query":"OpenAI Google AI Microsoft AI 新闻 昨天","freshness":"day"}'

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes an AI daily brief for AI industry news, which clearly justifies fetching/searching news and formatting output. However, this implementation uses child_process.execSync to invoke another script via a shell command, introducing command execution capability that is not an obvious requirement of producing a news brief and is materially broader than simple retrieval/formatting.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill sends search queries to an external search backend via the Tavily helper without explicit disclosure or user consent. In a daily-brief context this may leak usage patterns, interests, or future expansions of user-provided search terms to a third party, creating a privacy and data-governance risk even though the current queries are hardcoded.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script builds a shell command string and executes it via execSync to invoke another Node script. While there is internal logging about search progress, there is no explicit warning or confirmation that the skill will spawn a subprocess, which is a safety-relevant operation for code files.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes an AI daily brief focused on collecting AI industry news, which obviously justifies making searches but not invoking local subprocesses. This file uses child_process.execSync to execute another script by absolute path, introducing code-execution capability beyond the stated content-gathering role.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code explicitly formats time using the zh-CN locale, and the generated brief content and console output are written in Chinese throughout the file. This imposes a specific language/locale choice without offering the user an option to select another language or locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The file-level comments describe the script purpose and priority entirely in Chinese, while the executable behavior and logs are otherwise mixed-language. This creates a natural-language locale constraint without any user opt-in or justification that the skill is intended only for Chinese-speaking users.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/daily-brief.mjs:26

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/search-tavily.mjs:26