T09 · Insecure Skill Coding Practices
- Location
scripts/law_search.sh:10- Finding
Plaintext API-Key Transmission and Python Code Injection in Law Search
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Korean legal search skill is purpose-aligned, but its scripts expose API keys and legal queries over plaintext HTTP and contain command-execution injection risks.
Review before installing. Use only with non-sensitive queries until the scripts are fixed to use HTTPS, pass user input as data rather than Python source, validate numeric and ID parameters, and store API credentials with restrictive permissions. Be aware that legal questions and results may be sent to government APIs and, if enabled, to additional services such as search, Notion, or Telegram.
scripts/law_search.sh:10Plaintext API-Key Transmission and Python Code Injection in Law Search
scripts/case_search.sh:10Plaintext API-Key Transmission and Python Code Injection in Case Search
scripts/life_law.sh:10Plaintext API-Key Transmission and Python Code Injection in Everyday-Law Search
scripts/law_detail.sh:10Plaintext API-Key Transmission and Python Code Injection in Statute Detail Retrieval
SKILL.md:140Credential Setup Instructions Do Not Enforce Restrictive Permissions
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
|-----|-------|
| Provider | MOLEG (Ministry of Government Legislation) |
| API Source | law.go.kr (primary) + data.go.kr (fallback) |
| Auth (law.go.kr) | `~/.config/law-go-kr/credentials.json` → OC code |
| Auth (data.go.kr) | `~/.config/data-go-kr/api_key` |
| Daily limit | 10,000 calls |
| Playbook | `playbook.md` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
|-----|-------|
| Provider | MOLEG (Ministry of Government Legislation) |
| API Source | law.go.kr (primary) + data.go.kr (fallback) |
| Auth (law.go.kr) | `~/.config/law-go-kr/credentials.json` → OC code |
| Auth (data.go.kr) | `~/.config/data-go-kr/api_key` |
| Daily limit | 10,000 calls |
| Playbook | `playbook.md` |
The script fetches data from an external endpoint over plain HTTP, not HTTPS, while including the API key in the query string. This allows a man-in-the-middle to intercept or tamper with the response and steal the credential; because the response is then parsed and surfaced to the caller, attackers could inject false legal data or trigger downstream issues from malicious content.
ENCODED_QUERY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$QUERY'))")
RESPONSE=$(curl -s "http://apis.data.go.kr/1170000/caseSearch/caseSearchList.do?serviceKey=${API_KEY}&numOfRows=${NUM}&pageNo=1&type=XML&query=${ENCODED_QUERY}")
echo "$RESPONSE" | python3 -c "
import xml.etree.ElementTree as ET
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
API_KEY=$(cat ~/.config/data-go-kr/api_key)
# 법령 상세 조회
RESPONSE=$(curl -s "http://apis.data.go.kr/1170000/law/lawServiceDtl.do?serviceKey=${API_KEY}&target=law&MST=${LAW_ID}&type=XML")
echo "$RESPONSE" | python3 -c "
import xml.etree.ElementTree as ET
The script uses plain HTTP to contact the external API, sending the API key and query in cleartext over the network. That allows man-in-the-middle attackers or network observers to read or tamper with the response, potentially stealing the key, altering legal search results, or injecting malicious XML/error content into downstream processing.
ENCODED_QUERY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$QUERY'))")
RESPONSE=$(curl -s "http://apis.data.go.kr/1170000/law/lawSearchList.do?serviceKey=${API_KEY}&target=law&query=${ENCODED_QUERY}&numOfRows=${NUM}&pageNo=1")
echo "$RESPONSE" | python3 -c "
import xml.etree.ElementTree as ET
The script performs an outbound request over plain HTTP and includes the API key directly in the URL query string, exposing both the credential and the user's search terms to interception, proxy logs, and other network observers. Because this is a legal-information skill, the query content may be especially sensitive, making insecure transport materially more dangerous in context.
ENCODED_QUERY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$QUERY'))")
RESPONSE=$(curl -s "http://apis.data.go.kr/1170000/lifeLawSearch/lifeLawSearchList.do?serviceKey=${API_KEY}&numOfRows=${NUM}&pageNo=1&type=XML&query=${ENCODED_QUERY}")
echo "$RESPONSE" | python3 -c "
import xml.etree.ElementTree as ET
The skill documents shell scripts and outbound API usage but does not declare an explicit tool scope such as allowed tools or permissions. That mismatch can lead to over-broad execution in an agent runtime, where a legal search skill could invoke shell or network capabilities beyond what reviewers expect.
The skill includes connectors for saving results to Notion and sending alerts via Telegram even though its stated purpose is legal research. These extra data sinks can exfiltrate sensitive user legal questions, search results, or case details to unrelated services if the runtime enables them.
The manifest frames the skill as using law.go.kr and data.go.kr, but later documentation adds web_search fallback and Brave Search as supplementary capability. This creates scope drift: an agent may send user legal queries to additional third parties not disclosed in the primary description, weakening reviewability and data-flow transparency.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
### 법제처 국가법령정보 API (주 API)
1. [open.law.go.kr](https://open.law.go.kr) 회원가입
2. OC 코드 발급 (이메일 @ 앞부분)
3. `mkdir -p ~/.config/law-go-kr && echo '{"oc":"YOUR_OC"}' > ~/.config/law-go-kr/credentials.json`
### data.go.kr 판례 API (보조)
1. [data.go.kr](https://www.data.go.kr) 회원가입 → 인증키 복사
The playbook explicitly requires output in Korean, which is a natural-language locale constraint. Under the policy, forcing a specific language without user opt-in is a reportable violation unless the regional constraint is clearly justified, which is not stated here.
The script reads a local API key from disk and immediately sends a user-supplied query to an external service without any disclosure or consent prompt. In an agent skill context, this can cause unintended transmission of user-provided legal queries and use of a sensitive credential, creating privacy, auditing, and secret-handling concerns even if the functionality is expected.
The script sends the API key as a query parameter over plain HTTP, so anyone on the network path can observe or modify the request and recover the credential. Because the response is then trusted and parsed, an active attacker could also tamper with legal content returned to the user, making this more dangerous in a law-search skill where integrity of retrieved statutes matters.
The script reads a local API key from the user's home directory and transmits it to a third-party API without any disclosure or consent at runtime. In this skill context that behavior is expected for API-backed functionality, but it still creates a confidentiality risk because the secret is sent over an insecure channel and users are not informed that a local credential will be used.
The script silently reads a local API credential from ~/.config/data-go-kr/api_key without any user-facing disclosure, which can violate least surprise and user consent expectations. In an agent skill context, undisclosed credential access is risky because users may not realize local secrets are being consumed on their behalf.
The script sends both the user's legal query and the API key to a remote service without explicit disclosure, and it does so over plain HTTP. In a legal-search skill, user queries may contain sensitive personal legal issues, so undisclosed transmission increases privacy and credential-exposure risk.
The file is primarily written in English, but the setup section switches to Korean for critical installation steps. This can impose a language/locale constraint on users without opt-in or an explicit statement that the skill is intended only for Korean-speaking users.
The natural-language comments and argument error message are written only in Korean, which imposes a specific language on users without opt-in or documented justification. This is a language policy issue under the natural-language policy rule because the skill does not offer any locale choice.
The natural-language comments and user-visible error text are entirely in Korean, including usage guidance and runtime messages, with no indication that the skill is intentionally limited to Korean-speaking users. This can violate language/locale policy when no user opt-in or documented locale justification is provided.
The natural-language comments, usage text, and runtime error messages are written only in Korean, which imposes a specific language without any opt-in or alternative. The policy calls for flagging language or locale constraints when the skill forces a specific language without user choice or documented justification.
The natural-language strings in comments, usage text, and error messages are exclusively in Korean, with no indication that the skill is intentionally limited to Korean users or that language selection is supported. This can violate the language/locale policy when a specific language is imposed without opt-in or documented justification.
The manifest describes a Korean law and case search skill, which justifies calling legal-information APIs, but it does not suggest local credential-file access as part of the skill's scope. Reading ~/.config/data-go-kr/api_key introduces a local filesystem capability beyond the user-facing legal-search purpose.
No suspicious patterns detected.