Back to skill

Security audit

Africa

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a simple Africa policy query demo, but it can return and cache configured API keys in normal query results.

Review before installing if you plan to configure real API keys. Do not put secrets directly in dataSources unless the code is changed to keep credentials out of returned results, logs, and the in-memory cache.

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
index.js:85
Finding

Configured API credentials are exposed in policy query results

Content
View full analysis

Vulnerability Details

File Location: index.js:85-86, index.js:95-105, and index.js:114-123; the vulnerable configuration pattern is documented in README.md:53-55 and README.md:85-90.
Vulnerability Type: Sensitive credential exposure through returned application data
Risk Level: Medium

Vulnerable Code

README.md:53-55 instructs users to store API keys directly in dataSources:

javascript
dataSources: {
  investment: process.env.INVESTMENT_API_KEY || '[replace with your API key]',
  trade: process.env.TRADE_API_KEY || '[replace with your API key]'
}

index.js:85-86 retrieves that configured value:

javascript
const dataSource = this.config.dataSources[category];
const policies = await this.fetchFromDataSource(dataSource, category, options);

index.js:95-105 places the value in each policy record:

javascript
async fetchFromDataSource(dataSource, category, options) {
  const policies = [{
    title: this.config.language === 'zh-CN' ? '${name} investment policy' : '${name} Investment Policy',
    description: this.config.language === 'zh-CN'
      ? '${name} latest investment policies and regulations'
      : 'Latest investment policies and regulations in ${name}',
    effectiveDate: '2026-01-01',
    authority: this.config.language === 'zh-CN' ? '${name} government' : '${name} Government',
    dataSource,

index.js:114-123 also places the value in the top-level response:

javascript
return {
  country: this.t('country'),
  category: this.t('categories', category),
  totalPolicies: policies.length,
  policies: policies,
  lastUpdated: new Date().toISOString(),
  dataSource,
  language: this.config.language
};

Technical Analysis

The documentation defines dataSources as a place to supply environment-derived API keys. The implementation does not keep those credentials confined to an authentication boundary. Inst ...[truncated 2087 chars]

Remediation
View remediation

Remediation Suggestions

  1. Separate source identity, endpoint information, and authentication material:

    javascript
    dataSources: {
      investment: {
        id: 'investment-policy-api',
        url: process.env.INVESTMENT_API_URL,
        apiKey: process.env.INVESTMENT_API_KEY
      }
    }
    
  2. Use the credential only inside the network authentication layer. Never add apiKey, authorization headers, tokens, or raw configuration objects to returned policy records.

  3. Return only a non-sensitive source identifier when provenance is needed:

    javascript
    return {
      country: this.t('country'),
      category: this.t('categories', category),
      totalPolicies: policies.length,
      policies,
      lastUpdated: new Date().toISOString(),
      sourceId: source.id,
      language: this.config.language
    };
    
  4. Ensure cached objects contain policy data only and do not contain credentials or authorization headers.

  5. Add automated tests that configure a unique sentinel secret, execute every public method, serialize the results, and assert that the sentinel does not appear.

  6. Apply response redaction to sensitive field names such as apiKey, token, secret, and authorization as defense in depth.

  7. Update the documentation to distinguish API endpoints from API keys and explain that credentials must never be returned, logged, or embedded in policy data.

  8. Rotate any real credentials that may already have been exposed through returned results, application logs, telemetry, or downstream agent transcripts.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README shows very broad trigger phrases such as asking how to do business in Africa or to monitor policy changes, which are common business queries rather than clearly scoped skill invocations. In an agent ecosystem, this can cause the skill to activate unexpectedly and handle requests beyond explicit user intent, increasing the chance of over-broad data access, unintended tool use, or misleading policy analysis in the wrong context.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The header comment states '支持多语言: zh-CN,en-US,fr-FR', implying French is supported. However, getTranslations only defines zh-CN and en-US, and setLanguage explicitly restricts supported languages to ['zh-CN', 'en-US'], so the documented capability contradicts the actual code behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The header states '支持多语言: zh-CN,en-US,fr-FR', but the actual translation map and supported language list only include zh-CN and en-US. This creates a natural-language locale policy inconsistency because users are told a French locale is supported when the skill does not actually offer that choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file states that the skill supports Chinese and U.S. English and performs automatic language detection and switching. Automatically forcing locale behavior without explicit user choice can conflict with language/locale policy expectations unless opt-in or clear justification is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The package description is written entirely in Chinese, and the manifest provides no indication that language selection is optional or that the skill is limited to Chinese-speaking users. Under the policy, forcing a specific language without user opt-in can be 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
82% confidence
Finding

The script announces and exercises the skill in Chinese first, and explicitly sets the language to 'zh-CN' before any user choice is obtained. This can be a locale-policy concern because the file presents a fixed language preference rather than offering user selection at the point of use.

Content

No source excerpt is available for this finding.