Back to skill

Security audit

News Briefing

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its implementation exposes users to command-injection and credential-handling risks when generating and sending news briefings.

Review before installing. Use this only with trusted operators and trusted input values, avoid untrusted topics/titles/target-user values, and do not provide production Feishu credentials until the scripts are changed to use fetch or execFile/spawn with argument arrays, validate inputs and links, keep secrets out of command strings, and require confirmation before sending real Feishu messages.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/news-digest.mjs:75
Finding
Shell Command Injection in News Orchestration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/news-digest.mjs`, lines 75–85 and 108–113 **Vulnerability Type**: OS command injection through shell command construction **Risk Level**: High ### Vulnerable Code ```js const envStr = [ process.env.PERPLEXITY_API_KEY ? `PERPLEXITY_API_KEY=${process.env.PERPLEXITY_API_KEY}` : '', process.env.PPIO_API_KEY ? `PPIO_API_KEY=${process.env.PPIO_API_KEY}` : '', process.env.HTTPS_PROXY ? `HTTPS_PROXY=${process.env.HTTPS_PROXY}` : '', ].filter(Boolean).join(' '); const insightFlag = noInsight ? '--no-insight' : ''; const cmd = `${envStr} node "${fetchScript}" --topic "${topic}" --count ${count} --category ${category} --date "${dateStr}" --output json ${insightFlag}`; const raw = execSync(cmd, { timeout: 120000, env: process.env }).toString().trim(); ``` ```js const sendScript = join(__dir, 'send-card.mjs'); const sectionsJson = JSON.stringify(sections).replace(/'/g, "'\\''"); const userFlag = targetUser ? `--target-user "${targetUser}"` : ''; const dryFlag = dryRun ? '--dry-run' : ''; const sendCmd = `FEISHU_APP_ID=${process.env.FEISHU_APP_ID} FEISHU_APP_SECRET=${process.env.FEISHU_APP_SECRET} TARGET_USER_ID=${process.env.TARGET_USER_ID || ''} node "${sendScript}" --title "${cardTitle}" --subtitle "${subtitle}" --json '${sectionsJson}' ${userFlag} ${dryFlag}`; const result = execSync(sendCmd, { timeout: 30000, env: process.env }).toString(); ``` ### Technical Analysis The script constructs command strings by directly interpolating command-line arguments and environment variables, then passes those strings to `execSync()`. When `execSync()` receives a string, Node.js invokes a shell to interpret it. Several interpolated values are attacker-influenced: - `topic` originates from `--topics`. - `category` originates from `--categories` and is unquoted. - `dateStr` originates from `--date`. - `cardTitle` can originate from `--title`. - `targetUser` originates from `--target-user`. - API keys, proxy s ...[truncated 2082 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace command-string execution with argument-array APIs that do not invoke a shell: ```js import { execFileSync } from 'child_process'; const raw = execFileSync( process.execPath, [ fetchScript, '--topic', topic, '--count', String(count), '--category', category, '--date', dateStr, '--output', 'json', ...(noInsight ? ['--no-insight'] : []), ], { timeout: 120000, env: process.env, encoding: 'utf8', } ).trim(); ``` 2. Invoke `send-card.mjs` in the same manner, passing every option as a separate array element and using `shell: false`. 3. Pass credentials only through the `env` option. Do not insert them into command text. 4. Restrict `category` to the documented allowlist: `AI`, `GEO`, `SPORT`, `BIZ`, or `CUSTOM`. 5. Validate counts as bounded positive integers and validate dates against an expected date format. 6. Apply reasonable length limits to topics, titles, and user identifiers. 7. Add regression tests using quotes, semicolons, backticks, newlines, and `$()` expressions to confirm that values remain literal arguments. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch-news.mjs:41
Finding
Shell Command Injection in External API Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-news.mjs`, lines 41–46 and 116–125 **Vulnerability Type**: OS command injection through dynamically generated curl commands **Risk Level**: High ### Vulnerable Code ```js function curlPost(url, headers, body, proxy, timeoutMs = 30000) { const headerArgs = Object.entries(headers).map(([k, v]) => `-H "${k}: ${v}"`).join(' '); const proxyArg = proxy ? `--proxy ${proxy}` : ''; const escaped = JSON.stringify(body).replace(/'/g, "'\\''"); const cmd = `curl -s --max-time ${Math.floor(timeoutMs / 1000)} ${proxyArg} -X POST "${url}" ${headerArgs} -d '${escaped}'`; return JSON.parse(execSync(cmd, { timeout: timeoutMs + 2000 }).toString()); } ``` ```js const escaped = JSON.stringify({ model: 'pa/claude-haiku-4-5-20251001', messages: [{ role: 'user', content: prompt }], max_tokens: 400, }).replace(/'/g, "'\\''"); const proxyArg = proxy ? `--proxy ${proxy}` : ''; const cmd = `curl -s --max-time 20 ${proxyArg} -X POST "https://api.ppinfra.com/v3/openai/chat/completions" -H "Content-Type: application/json" -H "Authorization: Bearer ${ppioKey}" -d '${escaped}'`; const data = JSON.parse(execSync(cmd, { timeout: 22000 }).toString()); ``` ### Technical Analysis The script uses `execSync()` with dynamically constructed curl command strings. This unnecessarily places API requests behind a shell interpreter. The proxy value is read from `HTTPS_PROXY` or `https_proxy` and inserted without quoting: ```js const proxy = process.env.HTTPS_PROXY || process.env.https_proxy || ''; ``` The Perplexity and PPIO API keys are inserted into double-quoted header arguments. Shell command substitutions remain active inside double quotes. Thus, a malicious or compromised proxy or credential environment value can alter the command or cause a separate command to execute. The request body receives limited single-quote escaping, but this does not make the complete command safe because other command components rem ...[truncated 1758 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer Node.js `fetch()` for the Perplexity and PPIO HTTPS requests rather than invoking curl. 2. If proxy support is required, use a maintained proxy dispatcher or agent whose configuration is passed as data rather than shell syntax. 3. If curl must be retained, invoke it with `execFileSync()` or `spawnSync()` and an argument array: ```js const args = [ '-s', '--max-time', String(Math.floor(timeoutMs / 1000)), ...(proxy ? ['--proxy', proxy] : []), '-X', 'POST', url, ...Object.entries(headers).flatMap(([key, value]) => [ '-H', `${key}: ${value}`, ]), '-d', JSON.stringify(body), ]; const output = execFileSync('curl', args, { timeout: timeoutMs + 2000, encoding: 'utf8', shell: false, }); ``` 4. Do not pass API keys through command strings. Keep secrets in HTTP header data handled directly by the HTTP client. 5. Validate proxy URLs using `new URL()` and restrict accepted protocols to those explicitly supported. 6. Avoid including complete HTTP responses or authorization headers in error messages. 7. Add tests with malicious proxy and key values to verify that metacharacters cannot trigger shell evaluation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/news-digest.mjs:112
Finding
Feishu Application Secret Exposed in Child Process Command Line<![CDATA[ ## Vulnerability Details **File Location**: `scripts/news-digest.mjs`, line 112 **Vulnerability Type**: Sensitive credential exposure through process command-line metadata **Risk Level**: Medium ### Vulnerable Code ```js const sendCmd = `FEISHU_APP_ID=${process.env.FEISHU_APP_ID} FEISHU_APP_SECRET=${process.env.FEISHU_APP_SECRET} TARGET_USER_ID=${process.env.TARGET_USER_ID || ''} node "${sendScript}" --title "${cardTitle}" --subtitle "${subtitle}" --json '${sectionsJson}' ${userFlag} ${dryFlag}`; ``` The resulting command is executed as follows: ```js const result = execSync(sendCmd, { timeout: 30000, env: process.env }).toString(); ``` ### Technical Analysis The Feishu application ID and secret are copied into an environment-assignment prefix embedded directly in a shell command string. At the same time, `execSync()` already receives `env: process.env`, so embedding the credentials in the command text is redundant. While the child shell is active, the full shell command may be visible through operating-system process metadata or process-monitoring tools. Whether another process can read that metadata depends on operating-system hardening and account boundaries, but same-user processes and sufficiently privileged local monitoring services commonly have such access. This exposure is separate from sending the secret to Feishu's official token endpoint. Supplying the application ID and secret to that endpoint is necessary for the documented Feishu delivery function. Copying those values into shell command text is not necessary. ### Attack Path 1. The Skill is launched with valid `FEISHU_APP_ID` and `FEISHU_APP_SECRET` environment variables. 2. `news-digest.mjs` embeds both values in the `sendCmd` string. 3. `execSync()` starts a shell whose command-line text includes the credentials. 4. During the execution window, another local process with permission to inspect process metadata reads the shell command line. 5. The observer extracts the Feishu ...[truncated 902 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all credential assignments from the command string. 2. Invoke the child script directly without a shell and provide credentials only through the child environment: ```js const childEnv = { ...process.env, FEISHU_APP_ID: process.env.FEISHU_APP_ID, FEISHU_APP_SECRET: process.env.FEISHU_APP_SECRET, TARGET_USER_ID: process.env.TARGET_USER_ID || '', }; const result = execFileSync( process.execPath, [ sendScript, '--title', cardTitle, '--subtitle', subtitle, '--json', sectionsJson, ...(targetUser ? ['--target-user', targetUser] : []), ...(dryRun ? ['--dry-run'] : []), ], { timeout: 30000, env: childEnv, encoding: 'utf8', shell: false, } ); ``` 3. Grant the Feishu application only the API permissions required to send the documented message type. 4. Rotate the Feishu application secret if there is evidence that process command lines were monitored or logged. 5. Ensure logs, exception handlers, process supervisors, and telemetry systems redact credential values. 6. Where supported, load secrets from a dedicated secret manager and limit their availability to the shortest necessary execution scope. ]]>
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (18)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises and operationalizes shell execution, network access, and use of environment-backed secrets, but it does not declare any tool scope such as permissions or allowed-tools. That creates an authorization gap: a broad-trigger skill can cause web requests, CLI execution, and secret-backed actions without explicit least-privilege boundaries or reviewer-visible constraints.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The file states that the agent summarizes top stories "in Chinese," and later emphasizes "全程中文输出" as a fixed behavior. This appears to force a specific language/locale without documenting user choice, opt-in, or a region-specific justification.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases are very broad and map to common conversational requests like asking for news or updates, making accidental invocation likely. In this skill's context, accidental invocation is more concerning because activation can lead to live web access and outbound Feishu delivery to a target user, potentially causing unintended data retrieval or message sending.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code builds a shell command string and passes it to execSync, incorporating dynamic values such as headers, URL, body, and proxy. Because proxy comes from environment variables and header values include secrets, this creates command-injection risk and expands the skill's capability from simple HTTP requests to arbitrary shell execution if any interpolated value is attacker-controlled.

External Transmission

Medium
Category
Data Exfiltration
Content
const headerArgs = Object.entries(headers).map(([k, v]) => `-H "${k}: ${v}"`).join(' ');
  const proxyArg = proxy ? `--proxy ${proxy}` : '';
  const escaped = JSON.stringify(body).replace(/'/g, "'\\''");
  const cmd = `curl -s --max-time ${Math.floor(timeoutMs / 1000)} ${proxyArg} -X POST "${url}" ${headerArgs} -d '${escaped}'`;
  return JSON.parse(execSync(cmd, { timeout: timeoutMs + 2000 }).toString());
}
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The prompt explicitly requires that titles and summaries 'must be in Chinese' and also says non-Chinese sources must be translated into Chinese. This imposes a fixed language policy in the skill's natural-language behavior without offering the user a language choice or documenting an opt-in.

External Transmission

Medium
Category
Data Exfiltration
Content
for (let attempt = 1; attempt <= 2; attempt++) {
    try {
      const data = curlPost(
        'https://api.perplexity.ai/chat/completions',
        { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
        { model: 'sonar', messages: [{ role: 'user', content: prompt }], max_tokens: 1500 },
        proxy,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The insight-generation path repeats the same unsafe pattern by constructing a curl command with interpolated proxy and API key data and executing it via execSync. This unnecessarily grants shell execution in a feature that only needs outbound HTTPS, so compromise of environment-controlled inputs could lead to arbitrary command execution and secret exposure.

External Transmission

Medium
Category
Data Exfiltration
Content
max_tokens: 400,
    }).replace(/'/g, "'\\''");
    const proxyArg = proxy ? `--proxy ${proxy}` : '';
    const cmd = `curl -s --max-time 20 ${proxyArg} -X POST "https://api.ppinfra.com/v3/openai/chat/completions" -H "Content-Type: application/json" -H "Authorization: Bearer ${ppioKey}" -d '${escaped}'`;
    const data = JSON.parse(execSync(cmd, { timeout: 22000 }).toString());
    return data.choices?.[0]?.message?.content?.trim() || '';
  } catch (e) {
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
max_tokens: 400,
    }).replace(/'/g, "'\\''");
    const proxyArg = proxy ? `--proxy ${proxy}` : '';
    const cmd = `curl -s --max-time 20 ${proxyArg} -X POST "https://api.ppinfra.com/v3/openai/chat/completions" -H "Content-Type: application/json" -H "Authorization: Bearer ${ppioKey}" -d '${escaped}'`;
    const data = JSON.parse(execSync(cmd, { timeout: 22000 }).toString());
    return data.choices?.[0]?.message?.content?.trim() || '';
  } catch (e) {
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The embedded text and comments describe the skill as producing Chinese content, including `50-60字,中文` and Chinese cover copy, which suggests a language-specific behavior. Under the policy rule, forcing a specific language without opt-in can be a locale-policy violation unless the regional constraint is clearly justified.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The manifest describes a news briefing workflow, where network retrieval and message delivery are expected. However, this file implements that workflow by spawning subprocesses via execSync and interpolating user-controlled values such as topics, title, and target user into shell command strings, which is a broader and more dangerous capability than the stated purpose requires.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script builds a shell command string with user-controlled values such as topic, date, count/category-derived fields, and optional flags, then executes it with execSync. Quoting is incomplete and brittle for shell metacharacters like embedded double quotes or command substitutions, so an attacker can potentially achieve command injection and run arbitrary commands in the agent environment, with access to environment secrets included in the same execution context.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This command passes FEISHU_APP_ID and FEISHU_APP_SECRET into a child process and sends the assembled news digest to a target user, which is a network/data-transmission action. The code logs that it is building a card, but it does not explicitly warn that content will be delivered externally via Feishu using configured credentials.

External Transmission

Medium
Category
Data Exfiltration
Content
}

async function fetchFeishuToken(appId, appSecret) {
  const res = await fetch('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ app_id: appId, app_secret: appSecret }),
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
}

async function sendCard(token, userId, card) {
  const res = await fetch('https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id', {
    method: 'POST',
    headers: { 'Authorization': token, 'Content-Type': 'application/json' },
    body: JSON.stringify({
Confidence
82% confidence
Finding
This code transmits fully attacker-influenced content (`title`, `summary`, `insight`, and `url` from the input JSON) to an external messaging platform and ultimately to an end user without validation or sanitization. In this skill context, that can enable phishing or social-engineering delivery through trusted Feishu cards, especially because arbitrary URLs are embedded as '查看原文' buttons and rich markdown content is forwarded as-is.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This code writes a temporary JavaScript file and then invokes `node -e` through `execSync`, which are safety-relevant operations for a code file. Although the header comment states the output path, there is no confirmation prompt and no user-facing warning around the temporary file creation or subprocess execution itself.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
The date formatting is hard-coded to zh-CN and Asia/Shanghai, and the surrounding usage/comments are also Chinese-only, with no option for users to choose another locale. This can violate language/locale policy when a skill imposes a specific locale without explicit opt-in or documented regional justification.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/fetch-news.mjs:46

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/gen-cover.mjs:197

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/news-digest.mjs:88

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/send-card.mjs:165