Back to skill

Security audit

nonferrous-daily

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed metals-market reporting tool that fetches public data, keeps local report history, and sends reports to a user-configured Telegram chat.

Install only if you are comfortable configuring a Telegram bot token and having generated market reports sent to that chat, especially if you enable the daily cron. Use DRY_RUN first, keep unrelated secrets out of the project .env, and independently verify important price signals because the tool relies on third-party public data and one plaintext HTTP fallback source.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch-all-data.mjs:82
Finding

Market Data Retrieved over Unencrypted HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/fetch-all-data.mjs, lines 82–94 and 1256–1259
Vulnerability Type: Use of an unauthenticated plaintext market-data source
Risk Level: Medium

Vulnerable Code

js
// 1b. OmetalCN 長江現貨(GBK 頁面,備用源)
// URL: http://app.ometal.cn/data/mlist.asp
// 品種:Cu / Al / Pb / Zn / Ni / Sn + 升貼水
// 優勢:有 A00鋁(CCMN 常缺)、解析穩定、響應快
// ────────────────────────────────────────────

async function fetchOmetal() {
  try {
    const res = await fetch('http://app.ometal.cn/data/mlist.asp', {
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': 'text/html',
        'Referer': 'http://app.ometal.cn/',
      },

The untrusted response is later accepted as a fallback source:

js
aluminum: {
  usd: alumSpot.ok ? alumSpot.price : null,
  usdChangePct: alumSpot.ok ? alumSpot.changePct : null,
  usdUnit: 'USD/t',
  // v11: 優先 CCMN A00鋁 → 備用 OmetalCN A00鋁(SMM 無鋁 h5 頁面)
  cny: ccmn?.aluminum?.price ?? ometal?.aluminum?.price ?? null,
  cnyChange: ccmn?.aluminum?.updown ?? ometal?.aluminum?.change ?? null,
  cnySource: ccmn?.aluminum?.price != null ? 'CCMN' : (ometal?.aluminum?.price != null ? 'OmetalCN' : null),
},

Technical Analysis

The production data collector retrieves a price page through plain HTTP. HTTP provides neither transport confidentiality nor server authenticity. Any party able to intercept traffic between the host and app.ometal.cn—including a compromised gateway, hostile Wi-Fi access point, ISP-level intermediary, or poisoned network route—can modify the HTML response.

The application decodes and parses the response without cryptographic verification. If the preferred CCMN aluminum value is unavailable, the parsed Ometal value is accepted directly as the CNY aluminum price and exported in the collector's JSON output. There is no independent TLS-protected cross-check, deviation threshold, or plausibility rejection before accepting th ...[truncated 1516 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the HTTP endpoint with an HTTPS endpoint that presents a valid, trusted certificate.
  2. If the source does not support HTTPS, remove it from production fallback logic rather than accepting unauthenticated financial data.
  3. Cross-check fallback values against an independent TLS-protected source before exporting them.
  4. Enforce plausibility controls, including:
    • Maximum day-over-day change thresholds.
    • Expected numeric ranges.
    • Maximum deviation from other trusted sources.
    • Data freshness and date validation.
  5. Mark values as unavailable when validation fails instead of silently selecting the fallback.
  6. Remove aluminum collection entirely if it remains outside the Skill's declared scope, thereby reducing unnecessary network access and attack surface.
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
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (58)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

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

Content

Scanner excerpt · scripts/daily-report.mjs (reported line 471)May include surrounding context.

js
sh(`- ${points.trigger}`);
  lines.push('');

  lines.push('4) 关键风险');
  for (const r of risks) lines.push(`- ${r}`);
  lines.push('');

  lines.push(`数据源与时间戳:Yahoo/CCMN/SMM/Westmetall/GoogleNews/Reddit;生成时间 ${new Date().toISOString()}`);

  return { message: lines.join('\n'), records };
}

async function sendTelegram(token, chatId, text) {
  const url = `https://api.telegram.org/bot${token}/sendMessage`;
  const res = await fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json; charset=utf-8' },
    body: JSON.stringify({ chat_id: chatId, text }),
    signal: AbortSignal.timeout(15000),
  });
  const data = await res.json();
  if (!data.ok) throw new Error(`Telegram API error: ${JSON.stringify(data)}`);
  return data;
}

function saveReportState(state) {
  try {
    const dir = join(PROJECT_ROOT, 'memory');
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
    writeFileSync(REPORT_CACHE_PATH, JSON.stringify(sta

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 64)May include surrounding context.

2. Configure environment

bash
cp .env.example .env
# Edit .env with your Telegram bot token and chat ID

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/fetch-all-data.mjs # 採集數據(~5s)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/fetch-all-data.mjs # 採集數據(~5s)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/daily-report.mjs # 採集 + 生成 + 發送完整日報

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/daily-report.mjs # 採集 + 生成 + 發送完整日報

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/daily-report.mjs (reported line 14)May include surrounding context.

js
const execFileAsync = promisify(execFile);

function loadEnv() {
  const envPath = join(PROJECT_ROOT, '.env');
  const env = {};
  try {
    const content = readFileSync(envPath, 'utf-8');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fetch-prices.mjs (reported line 18)May include surrounding context.

js
const execFileAsync = promisify(execFile);

function loadEnv() {
  const envPath = join(PROJECT_ROOT, '.env');
  const env = {};
  try {
    const content = readFileSync(envPath, 'utf-8');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send-telegram.mjs (reported line 23)May include surrounding context.

js
const execFileAsync = promisify(execFile);

function loadEnv() {
  const envPath = join(PROJECT_ROOT, '.env');
  const env = {};
  try {
    const content = readFileSync(envPath, 'utf-8');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 65)May include surrounding context.

md
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fetch-prices.mjs (reported line 15)May include surrounding context.

js
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send-telegram.mjs (reported line 10)May include surrounding context.

js
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send-telegram.mjs (reported line 21)May include surrounding context.

js
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send-telegram.mjs (reported line 37)May include surrounding context.

js
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/send-telegram.mjs (reported line 83)May include surrounding context.

js
*   echo "消息文本" | node send-telegram.mjs
 *   node send-telegram.mjs < message.txt
 *
 * 從 .env 讀取 TELEGRAM_BOT_TOKEN 和 TELEGRAM_CHAT_ID
 */

import { readFileSync } from 'fs';

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description says to use the skill when the user needs "automated metals market monitoring" or "professional trading briefings," which are broad natural-language triggers rather than a narrow invocation condition. Although the domain is somewhat specialized, the file does not provide an explicit trigger list, scope boundary, or negative examples to clarify when the skill should or should not activate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The top-level description emphasizes market monitoring and briefings but does not clearly warn that running the skill may automatically send generated content to Telegram. In agent environments, undisclosed outbound messaging is dangerous because it can cause unintended external transmission of content, including sensitive context accidentally included in the report or confirmation messages.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This markdown template specifies all status, conclusion, evidence, execution, and invalidation fields in Chinese, which imposes a fixed language on skill output. Under the policy rule, a language constraint is a violation unless the skill offers user choice or clearly documents a justified locale-specific requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown playbook presents all operational guidance in Chinese and does not indicate that the user can choose another language or that the skill is intentionally limited to a Chinese-speaking or region-specific context. That can violate language/locale policy because it effectively forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes a data-collection and report-delivery skill for metals monitoring, but this file invokes child_process.execFile to launch fetch-all-data.mjs. Spawning subprocesses is a more powerful execution capability than straightforward data fetching or local backfill logic, and the manifest does not indicate any need for process execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code performs a full write to memory/signal-history.jsonl, replacing the file contents with merged data. While the script logs summary output afterward, there is no warning, confirmation, or inline comment/docstring disclosing that it will modify persisted history data before doing so.

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 collecting metals market data and delivering a report, but does not mention credential handling or local secret-file parsing. This file explicitly reads a project .env file for TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID, introducing credential access as an additional capability beyond straightforward market-data analysis logic.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes data collection and report delivery, but this implementation grants the skill the ability to execute another script via child_process.execFile. Subprocess execution is materially broader than ordinary HTTP-based data retrieval and is not declared in the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code emits natural-language content in Chinese, beginning with fixed Chinese strings in generated report text and continuing throughout the report and console messages. Because the file does not offer user opt-in or selection for language/locale, it violates the policy requirement to avoid forcing a specific language without user choice.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/daily-report.mjs:503