Back to skill

Security audit

Korean Invoice

Security checks for vulnerabilities and agentic risk

Overview

This Korean invoice skill is mostly purpose-aligned, but it has real safety issues around unsafe HTML/PDF rendering, path handling, and sensitive business data storage.

Review before installing. Use it only with trusted invoice data, avoid putting this skill directory in shared or synced repositories, protect the data/*.json and output files, and update dependencies. Do not let untrusted parties control client names, item names, notes, or issue dates until HTML escaping and output-path validation are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate.js:96
Finding

Unescaped Invoice Data Allows HTML and Script Injection During PDF Rendering

Content
View full analysis
{ const amount = item.quantity * item.price; itemRows += ` ${idx + 1} ${item.name} ${item.unit} ${formatCurrency(item.quantity)} ${formatCurrency(item.price)} ${formatCurrency(amount)} `; }); const html = template .replace(/{{myCompanyName}}/g, myInfo.companyName || '') .replace(/{{myBusinessNumber}}/g, myInfo.businessNumber || '') .replace(/{{myCEO}}/g, myInfo.ceo || '') .replace(/{{myAddress}}/g, myInfo.address || '') .replace(/{{myPhone}}/g, myInfo.phone || '') .replace(/{{myEmail}}/g, myInfo.email || '') .replace(/{{clientName}}/g, client.name || '') .replace(/{{clientBusinessNumber}}/g, client.businessNumber || '') .replace(/{{clientCEO}}/g, client.ceo || '') .replace(/{{clientAddress}}/g, client.address || '') .replace(/{{clientPhone}}/g, client.phone || '') .replace(/{{issueDate}}/g, issueDate) .replace(/{{validUntil}}/g, validUntil) .replace(/{{itemRows}}/g, itemRows) .replace(/{{subtotal}}/g, formatCurrency(subtotal)) .replace(/{{vat}}/g, formatCurrency(vat)) .replace(/{{total}}/g, formatCurrency(total)) .replace(/{{notes}}/g, options.notes || ''); ``` The tax-invoice generator has the same issue: ```js let itemRows = ''; itemList.forEach((item, idx) => { const amount = item.quantity * item.price; itemRows += ` ${issueDate} ${item.name} ${formatCurrency(item.quantity)} ${formatCurrency(item.price)} ${formatCurrency(amount)} ${options.notes ...[truncated 3315 chars]
Remediation
View remediation
`, `"`, and `'`. 2. Escape every scalar value before inserting it into an HTML text context, including supplier fields, client fields, item names, units, notes, dates, and invoice type. 3. Replace manual string concatenation and chained `replace()` calls with a template engine that enables automatic escaping by default. 4. Keep trusted template fragments, such as generated table-row structure, separate from untrusted text values. 5. Validate fields according to strict schemas: - Dates must match the expected date format. - Invoice type should be selected from an allowlist. - Numeric fields must be finite integers within acceptable business limits. - Text fields should have reasonable length limits. 6. Disable JavaScript while rendering invoices if scripts are not required: ```js await page.setJavaScriptEnabled(false); ``` 7. Add a restrictive Content Security Policy to both templates, for example one that denies scripts and external connections. 8. Consider request interception in Puppeteer and reject all network requests not required for local invoice rendering. 9. Add tests using payloads containing closing tags, script elements, event-handler attributes, and malformed table markup to verify that they are rendered only as text. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.js:32
Finding

Unvalidated Issue Date Allows Output Path Traversal and File Overwrite

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (23)

Known Vulnerable Dependency: basic-ftp==5.1.0 — 4 advisory(ies): CVE-2026-27699 (Basic FTP has Path Traversal Vulnerability in its downloadToDir() method); GHSA-6v7q-wjvx-w8wg (basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe); CVE-2026-41324 (basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl) +1 more

Critical
Category
Supply Chain
Confidence
91% confidence
Finding

The lockfile pins basic-ftp 5.1.0, which is reported with multiple serious advisories including path traversal, FTP command injection, and DoS conditions. In this package it appears only as a transitive dependency via get-uri/proxy-agent/puppeteer tooling, so exploitability depends on whether attacker-controlled FTP or proxy URLs are ever processed, but shipping a known-vulnerable version is still a real supply-chain risk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

설명은 문서 생성 및 세금 계산 자동화를 핵심 기능으로 제시하지만, 실제 코드는 거래처명, 사업자등록번호, 대표자, 주소, 연락처, 이메일 등을 clients.json에 저장하고 관리하는 명령행 도구입니다. 사업자등록번호 필드를 저장/표시하긴 하지만 검증이나 활용한 계산은 하지 않으며, 견적서나 세금계산서 파일 생성, 서식 출력, 금액 처리, 부가세 계산 로직이 전혀 없습니다. 따라서 선언된 목적과 실제 동작 사이에 중대한 불일치가 있습니다.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

코드는 manage-items.js로, items.json 파일을 사용해 품목 데이터를 CRUD하는 명령줄 스크립트다. add/edit/remove/list/view 명령만 구현되어 있으며, 문서 생성, 세금계산서 발행, 사업자 정보 관리, VAT 계산 등의 로직은 전혀 보이지 않는다. 따라서 선언된 설명과 실제 동작의 핵심 목적이 materially different 하며 명백한 설명-행동 불일치이다.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
95% confidence
Finding

extract-zip 2.0.1 is present with advisories for arbitrary file write via symlink/path traversal during archive extraction. Because this package is used by @puppeteer/browsers to unpack browser downloads, compromise of the archive source or a man-in-the-middle/proxy path could potentially write files outside the intended directory.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
84% confidence
Finding

ip-address 10.1.0 is flagged for parsing inconsistencies and XSS in HTML-emitting methods. Here it is a transitive dependency under socks/socks-proxy-agent/proxy support, so unless the skill exposes attacker-controlled IP parsing or renders those HTML helpers, practical impact is limited, but the vulnerable package is still present.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
93% confidence
Finding

ws 8.19.0 is a confirmed vulnerable WebSocket library version with reported memory disclosure and memory exhaustion issues. Since puppeteer-core depends on ws for browser protocol communication, exposure may exist if the skill connects to untrusted or attacker-influenced WebSocket endpoints, though local-only DevTools use would reduce practical risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README instructs users to store business registration numbers, addresses, phone numbers, email addresses, and bank account details in local JSON files, but provides no warning about the sensitivity of this data, access controls, or exclusion from version control and backups. In the context of an invoicing skill, this creates a realistic risk of unintended disclosure of business and personal information through repository commits, local compromise, or sharing of the skill directory.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README documents remove commands for clients and items without any confirmation, backup, or irreversibility warning. While this is more of a safety and integrity issue than a classic exploit path, users could easily destroy billing data needed for future invoices or records, especially in an agent-driven or automated environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README states that generated quotes and tax invoices are saved into an output directory, but does not warn that these documents may contain customer identifiers, business numbers, addresses, and financial amounts. Because invoice documents are commonly shared, synced, or left in predictable locations, the absence of handling guidance increases the chance of sensitive document exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill documents destructive commands that remove client and item records without any warning about permanence, confirmation, backup, or undo. While not an exploit primitive by itself, it creates a realistic risk of accidental data loss affecting billing records and business operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly stores sensitive business and personal information locally, including business registration numbers, addresses, phone numbers, email addresses, and bank account details, but gives no guidance on file permissions, encryption, retention, or secure handling. On shared systems or synced working directories, this can lead to unauthorized disclosure of financial and personally identifiable data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script persists client business and contact information to a local JSON file without any user-facing notice, consent flow, or explanation of retention. In the context of an invoice skill, this data can include sensitive business identifiers and personal contact details, creating privacy and data-handling risk if users are unaware it is being stored on disk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes a skill for automatically generating Korean quotes and tax invoices with business number and VAT calculation. This script implements full create, edit, delete, list, and view management of a persistent client database, which is a broader customer-management capability rather than an obvious implementation detail of document generation itself.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The removeClient function performs an irreversible update to the persisted client list by deleting a matching record and rewriting the data file. While it logs after deletion, there is no confirmation prompt, pre-action warning, or descriptive comment indicating that data will be removed, so the destructive operation lacks user disclosure.

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 presents all user-facing messages, errors, and usage instructions exclusively in Korean, including the main CLI help text. The file does not offer a language selection mechanism or document that the tool is intentionally Korea-specific, which creates a natural-language locale policy violation under the stated rules.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

All user-facing descriptive text and examples are presented only in Korean, with no indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This JSON file contains user-facing product names, units, and descriptions only in Korean, which can indicate a language/locale policy violation when no opt-in, fallback, or documented region-specific scope is present. Because SQP-3 applies to all file types and covers forced language/locale behavior, this is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The description states the skill is for '한국형' invoice/tax document generation, and the package metadata is entirely Korean-facing. This suggests a fixed language/locale orientation without any visible indication that users can opt into another language or locale, which may conflict with language/locale choice expectations.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The dependency uses a caret range (^23.0.0), which permits automatic installation of newer minor and patch releases. This can introduce supply-chain risk because builds may become non-reproducible and could pull in a compromised or breaking upstream version without review.

Content

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

json
"author": "무펭이",
  "license": "MIT",
  "dependencies": {
    "puppeteer-core": "^23.0.0"
  }
}

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This JavaScript file uses Korean-only natural-language comments and user-facing output such as usage text and error messages. Under the language/locale policy rule, forcing a specific language without user opt-in is a policy concern when no alternative locale or selection mechanism is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings throughout the script, including errors, success messages, empty-state text, and usage instructions, are written only in Korean. Because the file does not provide a language option or explain that the tool is intentionally limited to a Korean-speaking context, this is a language/locale policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The HTML root sets lang="ko", and the document content is primarily fixed in Korean, which imposes a specific language/locale by default. The file does not indicate user opt-in or explain that the template is intentionally limited to a Korea-specific business context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The HTML document declares lang="ko" and the visible invoice content is written in Korean, which imposes a specific language/locale by default. Under the policy rule, locale-specific behavior should either offer user choice or clearly document why the constraint is required.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.