Back to skill

Security audit

AI Customer Service KB Builder

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent FAQ-builder, but its website-scraping and CSV-export features are under-scoped enough that users should review it before installing.

Install only if you are comfortable with a local CLI that reads FAQ files, writes output files, and can fetch any URL it is given. Do not let untrusted users or prompts choose scrape URLs, especially in cloud or corporate networks, and treat CSV exports from scraped or third-party FAQ content as untrusted spreadsheet files.

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
kb-builder.js:108
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `kb-builder.js:108-127` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```javascript // Scrape FAQ from URL async function scrapeFromURL(url) { return new Promise((resolve, reject) => { const client = url.startsWith('https') ? https : http; client.get(url, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { // Simple HTML text extraction const text = data .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') .replace(/<[^>]+>/g, ' ') .replace(/&nbsp;/g, ' ') .replace(/\s+/g, ' ') .trim(); resolve(text); }); }).on('error', reject); }); } ``` The user-controlled URL reaches this function through the `scrape` command: ```javascript const url = getArg('--url'); const outputPath = getArg('--output') || './kb.json'; if (!url) { console.error('Error: --url is required'); process.exit(1); } console.log(`Scraping FAQ from ${url}...`); const text = await scrapeFromURL(url); const entries = parseFAQ(text); ``` ### Technical Analysis The application performs an outbound HTTP or HTTPS request to a URL supplied through the `--url` argument. It does not validate the destination hostname, port, or resolved IP address and does not reject loopback, private, link-local, or other reserved address ranges. Consequently, the process can be instructed to connect to resources that are inaccessible to the external attacker but accessible from the host running the Skill. Potential targets include: - Services bound to `127.0.0.1` or `::1` - Services on private network ranges - Container or orchestration control endpoints - Link-local cloud metadata services - Unauthenticated internal administration interfaces The response is converted to text, parsed as FAQ conte ...[truncated 1375 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse input with `new URL()` and explicitly permit only `http:` and `https:`. 2. Adopt an allowlist of approved domains whenever the expected destinations are known. 3. Resolve the hostname before connecting and reject every address in loopback, private, link-local, multicast, documentation, carrier-grade NAT, and other reserved ranges for both IPv4 and IPv6. 4. Prevent DNS rebinding by connecting only to the validated resolved address while preserving the expected hostname for TLS verification. 5. If redirect support is added, repeat the complete validation process for every redirect destination and limit the number of redirects. 6. Reject nonstandard ports unless they are explicitly required. 7. Place outbound network restrictions around the process so that it cannot reach metadata endpoints, management networks, or internal services. 8. Avoid returning or persisting response bodies from destinations that have not passed validation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
kb-builder.js:108
Finding
Unbounded Remote Response Buffering Enables Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `kb-builder.js:108-127` **Vulnerability Type**: Denial of Service through unbounded network input **Risk Level**: Medium ### Vulnerable Code ```javascript // Scrape FAQ from URL async function scrapeFromURL(url) { return new Promise((resolve, reject) => { const client = url.startsWith('https') ? https : http; client.get(url, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { // Simple HTML text extraction const text = data .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') .replace(/<[^>]+>/g, ' ') .replace(/&nbsp;/g, ' ') .replace(/\s+/g, ' ') .trim(); resolve(text); }); }).on('error', reject); }); } ``` ### Technical Analysis The scraper appends every received chunk to a JavaScript string without imposing a maximum response size. It also does not configure connection, header, or body-read timeouts. A remote server can therefore send an extremely large response, stream data indefinitely, or transmit data slowly enough to retain process resources for an extended period. Repeated string concatenation and subsequent regular-expression processing can consume substantial memory and CPU. If Node.js reaches its heap limit, the process may terminate. The application also does not validate the HTTP status or content type before buffering and processing the body. ### Attack Path 1. An attacker controls or identifies an HTTP endpoint that returns a very large body or streams data indefinitely. 2. The attacker causes the Skill to execute `scrape --url` against that endpoint. 3. Each response chunk is appended to the in-memory `data` string with no byte limit. 4. The process continues allocating memory until the response ends or the Node.js heap is exhausted. 5. If the response eventually ends, several ...[truncated 581 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict maximum response size and abort the request as soon as the received byte count exceeds that limit. 2. Configure connection, header, idle, and total-operation timeouts. 3. Validate the response status and reject unexpected or unsuccessful responses. 4. Allow only expected textual content types and reject binary or unknown content. 5. Check `Content-Length` when present, while retaining a streaming byte counter because that header is not trustworthy. 6. Process content incrementally where practical instead of buffering the complete response. 7. Apply process or container memory, CPU, and execution-time limits as defense in depth. 8. Ensure aborted requests are destroyed and all rejection paths release associated resources. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
kb-builder.js:168
Finding
Unsafe CSV Export Permits Spreadsheet Formula Injection<![CDATA[ ## Vulnerability Details **File Location**: `kb-builder.js:168-178` **Vulnerability Type**: CSV formula injection and improper CSV escaping **Risk Level**: Medium ### Vulnerable Code ```javascript case 'csv': const csv = ['ID,Question,Answer,Keywords,Category'] .concat(kb.entries.map(e => `"${e.id}","${e.question}","${e.answer}","${e.keywords.join(';')}","${e.category}"` )) .join('\n'); fs.writeFileSync(outputPath, csv, 'utf8'); break; ``` ### Technical Analysis Knowledge-base properties are inserted directly into quoted CSV cells. The implementation does not: - Escape embedded double quotes according to CSV rules - Neutralize values beginning with spreadsheet formula characters such as `=`, `+`, `-`, or `@` - Normalize control characters that may affect spreadsheet parsing The knowledge-base entries may originate from attacker-controlled FAQ documents or scraped websites. When the exported file is opened in spreadsheet software, a cell beginning with a formula marker may be interpreted as a formula rather than inert text. The exact behavior and available formula features depend on the spreadsheet application and its security settings. Potential formula payloads can cause external requests, expose spreadsheet data, or present deceptive links and content. Embedded quotes can additionally break the intended CSV column structure. ### Attack Path 1. An attacker places a formula-like value in a source FAQ question or answer, such as a value beginning with `=`. 2. A user extracts or scrapes that content into a knowledge base. 3. The user invokes the `export` command with `--format csv`. 4. `exportKB()` inserts the value into the CSV without formula neutralization or correct quote escaping. 5. A victim opens the generated CSV in spreadsheet software. 6. The spreadsheet may evaluate the cell as a formula, potentially causing external network interaction, data disclosure, or deceptive content. ### Impact Assessment The vuln ...[truncated 529 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a maintained CSV serialization library rather than manually constructing rows. 2. Escape embedded double quotes by doubling them and correctly preserve line breaks and delimiters. 3. Treat all knowledge-base fields as untrusted data. 4. Before serialization, neutralize cells whose first non-whitespace character is `=`, `+`, `-`, or `@`, for example by prefixing an apostrophe where compatible with the intended consumer. 5. Also account for leading tabs, carriage returns, and other control characters that spreadsheet applications may ignore before formula detection. 6. Document that CSV exports contain untrusted content and should be imported with formula evaluation disabled. 7. Add tests covering formulas, embedded quotes, commas, newlines, control characters, and Unicode input. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The sample configuration hard-codes `language: zh-CN` and a Chinese fallback message, and the output schema later also fixes `language` to `zh-CN`. There is no accompanying note that other languages are supported or that Chinese is merely an example, which can violate language/locale choice policy.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The config sets the skill language to "zh-CN" with no indication that users can choose another language or opt in to this locale. The policy explicitly flags language or locale constraints when they are imposed without user choice or documented justification.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The default configuration hard-codes `language: 'zh-CN'` and a Chinese-only fallback message, which imposes a specific language/locale policy on users. The file does not offer a language choice at runtime or explain why the locale restriction is necessary.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The manifest declares a fixed language of "zh-CN", and the content is written exclusively in Simplified Chinese without any visible indication of user opt-in or that the skill is intentionally region-specific. Per policy, forcing a specific language/locale is a concern unless choice or clear justification is documented.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The keyword list for the return-policy FAQ includes very short fragments such as single-word or partial-word matches that can overlap with unrelated user inputs. In a retrieval or trigger-based assistant, this can cause unintended activation of the wrong entry, producing incorrect guidance and reducing the reliability of user-facing responses.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The payment FAQ uses broad partial keywords like short fragments of 'payment methods,' which are likely to match many unrelated finance or checkout questions. This can misroute users to a generic payment answer when they may be asking about billing failures, refunds, or other sensitive transaction topics.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The order-modification entry contains generic triggers such as '订单' and short partial forms that are common in many shopping conversations. In a skill that relies on keyword matching, this can cause the order-change response to override more appropriate order-status, cancellation, or shipping answers.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The example JSON schema presents `language: zh-CN` as the output value, reinforcing a Chinese-only default behavior. Without explicit opt-in or documentation of configurable locales, this suggests the skill is oriented to a single language by default.

Static analysis

No suspicious patterns detected.