Back to skill

Security audit

Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill is a Japan-focused M&A analysis helper that fetches or parses financial filings and writes reports, with no evidence of hidden persistence, destructive behavior, or unrelated data transfer.

Before installing, treat this as a Japanese public-filing due diligence assistant, not professional financial advice. Use it in a controlled workspace, avoid exposing unrelated environment variables, and be aware that EDINET_API_KEY could appear in logs on request failures unless errors are sanitized. Pin or review dependencies if reproducibility matters.

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

Warning
Location
scripts/fetch_edinet.py:45
Finding
EDINET API key may be disclosed through request URLs and exception logs## Vulnerability Details **File Location**: `scripts/fetch_edinet.py:45-46`, `scripts/fetch_edinet.py:70-71`, `scripts/fetch_edinet.py:138-140`, and `scripts/fetch_edinet.py:157-159` **Vulnerability Type**: Credential exposure through URL query parameters and unsanitized error logging **Risk Level**: Medium ### Vulnerable Code ```python def search_documents(api_key: str, target_date: str) -> list[dict]: """指定日の書類一覧を取得.""" url = f"{EDINET_BASE}/documents.json" params = {"date": target_date, "type": 2, "Subscription-Key": api_key} resp = httpx.get(url, params=params, timeout=30) resp.raise_for_status() data = resp.json() return data.get("results", []) ``` ```python def download_pdf(api_key: str, doc_id: str, output_dir: Path) -> Path | None: """EDINET から書類 PDF をダウンロード (ZIP展開).""" url = f"{EDINET_BASE}/documents/{doc_id}" params = {"type": 2, "Subscription-Key": api_key} # type=2: PDF resp = httpx.get(url, params=params, timeout=60) resp.raise_for_status() ``` ```python try: results = search_documents(api_key, check_date) except httpx.HTTPError as e: print(f" API エラー: {e}", file=sys.stderr) continue ``` ```python try: path = download_pdf(api_key, doc_id, output_dir) if path: downloaded.append(str(path)) print(f" ✓ 保存: {path}", file=sys.stderr) except httpx.HTTPError as e: print(f" ダウンロードエラー: {e}", file=sys.stderr) ``` ### Technical Analysis The `EDINET_API_KEY` secret is inserted into the URL query string as `Subscription-Key`. HTTP client exceptions may include the complete request URL in their string representation. The code writes raw `httpx.HTTPError` objects to standard error without redaction, creating a potential path for the API key to enter terminal histories, Agent logs, CI logs, centralized logging systems, or diagnostic records. Query-string credentials can also be retained ...[truncated 1767 chars]
Remediation
## Remediation Suggestions 1. Do not print raw exception objects for authenticated HTTP requests. Log a sanitized error type and status code instead: ```python except httpx.HTTPStatusError as e: print( f"EDINET API error: HTTP {e.response.status_code}", file=sys.stderr, ) except httpx.RequestError: print("EDINET API request failed", file=sys.stderr) ``` 2. If the EDINET API supports authentication through an HTTP header, place the subscription key in that header rather than the query string: ```python headers = {"Subscription-Key": api_key} params = {"date": target_date, "type": 2} resp = httpx.get(url, params=params, headers=headers, timeout=30) ``` 3. If EDINET requires the key as a query parameter, introduce explicit URL sanitization before any request-related information is logged. Replace the value of `Subscription-Key` with `[REDACTED]`. 4. Configure CI, Agent, and centralized logging systems to redact known credential parameter names, including `Subscription-Key`. 5. Rotate the current API key if existing logs may contain failed EDINET request URLs. Restrict access to historical logs and remove exposed copies where feasible. 6. Add automated tests that induce request and HTTP status failures, capture standard error, and assert that the configured API key never appears in output.

T08 · Insecure Dependencies

Note
Location
SKILL.md:5
Finding
Third-party Python dependencies are installed without version or integrity constraints## Vulnerability Details **File Location**: `SKILL.md:5` **Vulnerability Type**: Unpinned third-party dependencies and non-reproducible installation **Risk Level**: Low ### Vulnerable Code ```yaml metadata: {"openclaw":{"requires":{"bins":["python3"],"anyBins":["uv","pip3"]},"emoji":"🦞","os":["darwin","linux"],"install":[{"type":"uv","packages":["httpx","pdfplumber","openpyxl"]}]}} ``` ### Technical Analysis The Skill requests installation of `httpx`, `pdfplumber`, and `openpyxl` without exact versions, hashes, or a committed dependency lock file. Each installation can therefore resolve to a different package release. The package names are consistent with the Skill's declared network, PDF-processing, and spreadsheet-export functionality. No typo-squatted name, untrusted registry, or known malicious dependency is shown in the audited files. The risk arises from mutable dependency resolution: a compromised upstream release or an unsafe future release could be selected automatically without a new review of this Skill. Python packages may execute package-controlled behavior during installation or when imported by the scripts. Consequently, dependency resolution is part of the Skill's effective trusted code base. ### Attack Path 1. An attacker compromises an upstream package distribution channel or publishes a malicious release through a compromised maintainer account. 2. A user installs the Skill after that release becomes the version selected by the resolver. 3. Because no reviewed version or integrity hash is specified, the installation accepts the newly resolved artifact. 4. Malicious package behavior executes during installation or when `fetch_edinet.py`, `parse_pdf.py`, or `export_excel.py` imports the dependency. 5. The package obtains the privileges of the user or Agent process performing the installation or running the script. This is a supply-chain risk rather than evidence that any currently named dependency is ...[truncated 688 chars]
Remediation
## Remediation Suggestions 1. Pin every runtime dependency to an exact, reviewed version: ```yaml packages: - "httpx==<reviewed-version>" - "pdfplumber==<reviewed-version>" - "openpyxl==<reviewed-version>" ``` 2. Generate and commit a lock file using the selected package-management workflow so that direct and transitive dependencies resolve reproducibly. 3. Use hash verification where supported. Maintain hashes for all resolved wheels or source distributions and reject artifacts whose hashes do not match. 4. Install only from an explicitly configured trusted package index. Disable unneeded extra indexes to reduce dependency-confusion exposure. 5. Add automated dependency vulnerability and provenance scanning to the release process. Review updates before changing pinned versions. 6. Perform installation in an isolated virtual environment under a non-privileged account. Do not expose unrelated credentials or sensitive directories during dependency installation. 7. Retain only the three dependencies required by the declared features and periodically verify that each remains necessary.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The description promises substantive M&A analysis functionality: analyzing companies, valuating businesses, parsing 決算書, using public filings, and generating acquisition simulation reports. The actual code only formats input JSON into an Excel workbook. While the sheet names and labels are finance/M&A related, the code assumes all financial and valuation data are already provided. Its primary purpose is file export, not analysis. This is a material description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents a full analytical M&A/due-diligence capability. The supplied code only retrieves EDINET filings and stores downloaded PDFs/binary files. It does not inspect document contents, extract financial data, compute valuations, analyze companies, or generate reports. It also mentions 官報 in the description, but the implementation only calls the EDINET API and merely prints a manual 官報 URL on failure. This is a material description-behavior mismatch in primary purpose and capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description promises high-level financial and M&A analysis capabilities: company valuation, due diligence, acquisition simulations, and analysis of public filings. The supplied code does not perform any of those domain-specific tasks. Instead, it only parses a local PDF using pdfplumber, extracts text and tables, and outputs the raw content. While PDF extraction could be a supporting component for a due diligence system, this code chunk’s primary purpose is generic document extraction rather than M&A analysis. There is no valuation logic, no financial-statement interpretation, no EDINET/官報 integration, no company analysis, and no report generation. Therefore the description materially overstates and misrepresents the actual behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares no explicit tool scope or permission boundaries despite instructing use of environment variables, network retrieval, and local file write operations. That creates an over-privileged execution surface where the agent may access network, environment secrets, or write files without clear user-visible constraints, increasing the risk of unintended data access or exfiltration.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The invocation text uses broad trigger phrases like company valuation and due diligence without clear exclusion rules, making accidental or over-broad auto-invocation more likely. In a skill that can fetch network resources, parse user-supplied documents, and write outputs, overly permissive triggering can cause unintended tool use, unnecessary data processing, or surprising access patterns.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The instructions define the persona, tone, and reporting format entirely in Japanese and require specific Japanese phrasing conventions, but do not state that the user may choose another language. This can force a locale/language preference without user opt-in, which is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The file's docstring, CLI descriptions, error messages, sheet titles, and exported labels are all hard-coded in Japanese, which imposes a specific language/locale on all users. The file does not provide any opt-in, language selection, or justification that this is intentionally limited to a Japanese-only regional context.

External Transmission

Medium
Category
Data Exfiltration
Content
print("ERROR: httpx が必要です。`uv pip install httpx` を実行してください。", file=sys.stderr)
    sys.exit(1)

EDINET_BASE = "https://api.edinet-fsa.go.jp/api/v2"


def search_documents(api_key: str, target_date: str) -> list[dict]:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
This markdown reference forces a specific language/locale for users by providing all instructions and mappings only in Japanese. Under the policy, language constraints should either offer user choice or be clearly documented as a justified region-specific limitation.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The entire guide is written only in Japanese, with no indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified.

Description-Behavior Mismatch

Low
Confidence
84% confidence
Finding
The module docstring and CLI description describe the tool as extracting PDF text with page numbers, but the implementation also calls `extract_tables()` and emits table-specific sections. That is broader behavior than the stated purpose, even though it remains related to PDF parsing.

Static analysis

No suspicious patterns detected.