Back to skill

Security audit

Earnings Tracker

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its earnings-tracking purpose, but it can silently send an OpenAI API key to a different translation provider and includes an unused browser-automation dependency.

Review this skill before installing. Use only a Tavily key and a provider-specific `ZAI_API_KEY`; do not run it in an environment containing `OPENAI_API_KEY` unless the fallback is removed or network access is constrained. Expect company symbols and fetched financial text to be sent to Tavily and, by default, BigModel/GLM for translation. Remove or pin the unused Playwright dependency before production use.

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)

T09 · Insecure Skill Coding Practices

Error
Location
fetch-earnings.js:188
Finding

Cross-provider API credential disclosure through unsafe environment-variable fallback

Content
View full analysis

Vulnerability Details

File Location: fetch-earnings.js:188-199
Vulnerability Type: Cross-provider credential disclosure
Risk Level: High

Vulnerable Code

javascript
const apiKey = (process.env.ZAI_API_KEY ?? process.env.OPENAI_API_KEY ?? '').trim();
if (!apiKey) {
  return text; // No API key; return the original text
}

try {
  const resp = await fetch('https://open.bigmodel.cn/api/paas/v4/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },

Technical Analysis

The translation function first attempts to read ZAI_API_KEY, but falls back to OPENAI_API_KEY when the provider-specific key is unavailable. It then sends the selected value as a bearer credential to https://open.bigmodel.cn.

An OpenAI API key is intended for OpenAI-controlled endpoints and is unrelated to the declared BigModel/GLM translation provider. Forwarding that credential to another provider violates credential isolation and least-privilege principles. The network request itself is necessary for the optional translation feature, but access to OPENAI_API_KEY is not necessary and exceeds the minimum privileges required by the Skill.

The behavior is triggered automatically by commands that translate returned financial content. It does not require the user to explicitly authorize sending an OpenAI credential to BigModel.

Attack Path

  1. A user or agent environment contains a valid OPENAI_API_KEY.
  2. The environment does not contain ZAI_API_KEY, or it is unavailable to the process.
  3. The user invokes a translation-capable operation such as calendar, news, summary, or check without --no-translate.
  4. translateToChinese() selects OPENAI_API_KEY through the fallback expression.
  5. The function places that key in the HTTP Authorization header.
  6. The credential is transmitted to `open.bigm ...[truncated 717 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the OPENAI_API_KEY fallback and accept only the credential intended for the BigModel/GLM endpoint:

    javascript
    const apiKey = (process.env.ZAI_API_KEY ?? '').trim();
    
  2. Fail closed or return untranslated content when ZAI_API_KEY is absent. Never substitute a credential belonging to a different provider.

  3. Use explicit provider-specific configuration that binds each credential to an allowlisted hostname.

  4. Document exactly which endpoint receives the key and the financial text submitted for translation.

  5. Avoid logging authorization headers or provider error responses that could contain credential-related details.

  6. Revoke and rotate any OPENAI_API_KEY that may already have been exposed through this code path.

  7. Add an automated test confirming that OPENAI_API_KEY is never read or transmitted by the GLM translation function.

T08 · Insecure Dependencies

Note
Location
package.json:14
Finding

Unused Playwright dependency unnecessarily expands the installation attack surface

Content
View full analysis

Vulnerability Details

File Location: package.json:14-16
Vulnerability Type: Unnecessary third-party dependency
Risk Level: Low

Vulnerable Code

json
"dependencies": {
  "playwright": "^1.40.0"
}

Technical Analysis

The reviewed JavaScript does not import or use Playwright. The Skill documentation also states that Playwright was removed in favor of direct API calls. Retaining the dependency therefore provides no capability required by the declared earnings-tracking functionality.

Although the reviewed evidence does not establish that the specified Playwright package is malicious, installing an unused package and its transitive dependency chain unnecessarily increases supply-chain, installation, maintenance, and browser-download exposure. This conflicts with least-privilege and minimal-dependency principles.

The version declaration also uses a range and the project structure contains no reviewed lockfile, reducing reproducibility of future installations.

Attack Path

  1. A user or deployment process runs the package manager installation command.
  2. The package manager resolves and installs Playwright and applicable transitive components despite the runtime not using them.
  3. Installation lifecycle behavior and additional package content execute or become available within the installation environment.
  4. A future compromised or vulnerable component in this unnecessary dependency path would create exposure that would not exist if the dependency were removed.

This is an attack-surface risk rather than evidence of active exploitation by the current package.

Impact Assessment

Potential impact is limited to the privileges of the account or build environment performing dependency installation. Depending on package-manager configuration, unnecessary dependencies can consume storage and network resources and expose the environment to additional supply-chain or installation-script risk. ...[truncated 149 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove Playwright from dependencies, because the current implementation uses the built-in fetch API and does not import Playwright.
  2. Regenerate the dependency metadata and lockfile after removal.
  3. If no external packages are required, remove the dependencies object entirely.
  4. Add dependency-review tooling to detect unused, vulnerable, or unexpectedly introduced packages.
  5. Commit a lockfile when third-party dependencies are genuinely required so installations are reproducible and reviewable.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (14)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill requires environment variables and makes outbound network requests, but it does not declare any explicit tool scope or permissions in the manifest. This can cause the agent platform or user to underestimate the skill's access level, reducing transparency and weakening least-privilege controls around secrets and network use.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Automatic Chinese translation is enabled by default, which means fetched content is sent to a translation provider without explicit user opt-in. While primarily a policy and privacy issue rather than direct code execution risk, it can still expose content externally and alter output language in ways the user did not request.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explains required API keys but does not clearly warn that user queries, company symbols, and fetched content will be sent to external services for search and translation. This creates a data disclosure risk because users may unknowingly transmit potentially sensitive interests or content to Tavily and GLM.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The invocation examples use broad natural-language requests like checking company news or tracking a company, without clear boundaries on when the skill should activate. This increases the risk of over-broad triggering, causing unintended external API calls, file writes, or background monitoring actions from ambiguous user prompts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill writes tracked company information to a local .tracked-companies.json file but does not clearly warn users before doing so. Undisclosed local persistence can create privacy, compliance, and surprise-behavior issues, especially in shared or managed environments where local files may be accessible to others.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The header states '中文翻译输出' as a built-in feature, and the implementation translates fetched content into Chinese by default unless the user explicitly disables it. This imposes a specific language/locale behavior without asking for user preference first, which matches the language-policy violation criteria.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · fetch-earnings.js (reported line 165)May include surrounding context.

js
body.days = options.days;
  }

  const resp = await fetch('https://api.tavily.com/search', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),

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 · fetch-earnings.js (reported line 165)May include surrounding context.

js
body.days = options.days;
  }

  const resp = await fetch('https://api.tavily.com/search', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This external transmission sends fetched content to the GLM translation API, creating a second outbound data flow that is not strictly necessary for core earnings lookup functionality. Because the text may contain third-party content or user-requested material, this increases privacy and compliance risk, especially since translation is enabled by default unless the user passes --no-translate.

Content

Scanner excerpt · fetch-earnings.js (reported line 194)May include surrounding context.

js
}

  try {
    const resp = await fetch('https://open.bigmodel.cn/api/paas/v4/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Fetched news content and AI-generated summaries are sent to a second external service for translation without an explicit user warning or consent. This creates an unnecessary data-sharing path and may expose third-party content, user-requested subjects, or potentially sensitive fetched text to another provider beyond the search API.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description uses Chinese exclusively for the skill's user-facing summary. Under the policy, forcing a specific language without offering user choice or documenting a justified locale constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The natural-language description includes Chinese text as the skill's presented description, but the file provides no indication that users can choose language or that the locale restriction is intentional. This can conflict with language/locale policy expectations when a skill implicitly targets a specific language without documenting opt-in or justification.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
83% confidence
Finding

The dependency uses a caret range (^1.40.0), allowing different Playwright versions to be installed over time. This weakens build reproducibility and can unintentionally introduce vulnerable or behavior-changing releases through the supply chain, which is relevant because this skill depends on browser automation software that may download and execute browser binaries.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
"author": "OpenClaw",
  "license": "MIT",
  "dependencies": {
    "playwright": "^1.40.0"
  }
}

Unverifiable Dependency: playwright has 1 known advisory(ies) (CVE-2025-59288 (Playwright downloads and installs browsers without verifying the authenticity of)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
76% confidence
Finding

The manifest references Playwright without exact pinning, while Playwright has a known advisory related to downloading and installing browsers without authenticity verification. Because the resolved version is not fixed, consumers may install an affected release, creating supply-chain risk where unverified browser binaries could be fetched and executed.

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
fetch-earnings.js:146