T09 · Insecure Skill Coding Practices
- Location
scripts/fetch_edinet.py:45- Finding
EDINET API key may be disclosed through request URLs and exception logs
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch_edinet.py:45-46,scripts/fetch_edinet.py:70-71,scripts/fetch_edinet.py:138-140, andscripts/fetch_edinet.py:157-159
Vulnerability Type: Credential exposure through URL query parameters and unsanitized error logging
Risk Level: MediumVulnerable 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) continuepython 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_KEYsecret is inserted into the URL query string asSubscription-Key. HTTP client exceptions may include the complete request URL in their string representation. The code writes rawhttpx.HTTPErrorobjects 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
View remediation
Remediation Suggestions
-
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) -
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) -
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-Keywith[REDACTED]. -
Configure CI, Agent, and centralized logging systems to redact known credential parameter names, including
Subscription-Key. -
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.
-
Add automated tests that induce request and HTTP status failures, capture standard error, and assert that the configured API key never appears in output.
-
