Back to skill

Security audit

唐诗宋词元曲查询 - 即刻数据

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its poetry-query purpose, but an undocumented endpoint override can redirect API-key-bearing requests to another server.

Review before installing. Use a limited, revocable JikeAPI key, keep JIKE_API_BASE_URL unset or locked to https://api.jikeapi.cn, and avoid running this skill in environments where untrusted users can set environment variables. Expect poetry query terms and the AppKey to be sent to the JikeAPI service.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/poetry_query.py:189
Finding

API Credential Exposure Through an Unvalidated Configurable Endpoint

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (7)

Tainted flow: 'url' from os.environ.get (line 189, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The request target is derived in part from JIKE_API_BASE_URL, which is taken directly from an environment variable and used for outbound network access. In an agent/runtime environment where untrusted parties can influence environment configuration, this can redirect requests and the appkey to an attacker-controlled host, causing SSRF-style egress and credential exfiltration.

Content

Scanner excerpt · scripts/poetry_query.py (reported line 191)May include surrounding context.

python
"""
    url = f"{API_BASE_URL}{API_PATH_MAP[command]}?{urllib.parse.urlencode({**params, 'appkey': appkey})}"
    try:
        with urllib.request.urlopen(url, timeout=15) as response:
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as exc:
        return {"code": exc.code, "message": f"接口请求失败: HTTP {exc.code}", "data": ""}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/poetry_query.py (reported line 58)May include surrounding context.

python
env_value = os.environ.get(env_name, "").strip()
        if env_value:
            return env_value
    env_file = Path(__file__).parent / ".env"
    if not env_file.exists():
        return ""
    for line in env_file.read_text(encoding="utf-8").splitlines():

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes a Python script, requires environment variables for API keys, and performs network access to a third-party service, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes it harder for a host agent to constrain file, environment, and network access, increasing the risk of overbroad capability use or unintended secret exposure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · _meta.json (reported line 8)May include surrounding context.

json
"title": "唐诗宋词元曲查询 - 即刻数据",
  "description": "支持古诗词列表、详情、诗人查询、诗人详情、随机诗词、词牌、朝代、类别和体裁查询。",
  "env": "JIKE_POETRY_QUERY_KEY",
  "api_url": "https://api.jikeapi.cn/v1/poetry/query",
  "homepage": "https://www.jikeapi.cn/"
}

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

This is a natural-language policy issue because the skill presents its purpose and usage only in a single language, which can force a locale choice on users without opt-in. The file contains Chinese-only docstrings and help text, but no indication that the skill is intentionally region-specific or that alternative languages are supported.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/poetry_query.py (reported line 159)May include surrounding context.

python
@return dict 接口业务参数
    """
    if args.command == "search":
        params = {name: getattr(args, name).strip() for name in ["name", "author", "dynasty", "type", "format"] if getattr(args, name).strip()}
        params["page"] = normalize_positive_int(args.page, "page")
        params["page_size"] = normalize_positive_int(args.page_size, "page_size", 50)
        return params

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/poetry_query.py (reported line 166)May include surrounding context.

python
if args.command == "detail":
        return {"poetry_id": normalize_positive_int(args.poetry_id, "poetry_id")}
    if args.command == "author":
        params = {name: getattr(args, name).strip() for name in ["name", "dynasty"] if getattr(args, name).strip()}
        params["page"] = normalize_positive_int(args.page, "page")
        params["page_size"] = normalize_positive_int(args.page_size, "page_size", 50)
        return params

Static analysis

No suspicious patterns detected.