Back to skill

Security audit

all in one skill for wencai 同花顺

Security checks for vulnerabilities and agentic risk

Overview

This finance-query skill is coherent, but it handles an API key and financial queries in ways that need careful review before use.

Install only if you trust the environment where it will run and can keep IWENCAI_BASE_URL fixed to the official HTTPS iWenCai endpoint. Prefer IWENCAI_API_KEY through a protected environment or secret store, avoid --api-key on the command line, and avoid sending private account identifiers or sensitive portfolio details in queries.

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/cli.py:19
Finding

Bearer API Key and User Queries Can Be Transmitted to an Arbitrary or Plaintext Endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/cli.py, lines 19–20 and 66–72
Vulnerability Type: Unrestricted destination for sensitive network transmission
Risk Level: High

Vulnerable Code

python
BASE_URL = os.environ.get("IWENCAI_BASE_URL", "https://openapi.iwencai.com").rstrip("/")
API_KEY  = os.environ.get("IWENCAI_API_KEY", "")
python
def _post(url: str, payload: dict, timeout: int = 30) -> dict:
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type":  "application/json",
    }
    body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    req  = urllib.request.Request(url, data=body, headers=headers, method="POST")

The affected URL construction and invocation occur at lines 88 and 100:

python
url = f"{BASE_URL}/v1/query2data"
python
url = f"{BASE_URL}/v1/comprehensive/search"

Technical Analysis

The Skill must communicate with the remote iWenCai API to provide its declared financial-query functionality. Sending a bearer API key and the user's financial query to the legitimate API is therefore functionally necessary.

However, IWENCAI_BASE_URL is trusted without validating its scheme, hostname, port, or other URL components. The _post function attaches the bearer credential to every request made to the resulting URL. A custom value may consequently redirect both the credential and user-supplied query to an unrelated server.

The implementation also permits an http:// endpoint. In that case, the bearer token and query can be transmitted without transport encryption and may be observable by systems on the network path. This behavior exceeds minimum privilege because the credential should only be disclosed to the intended API service or an explicitly trusted endpoint.

Attack Path

  1. An attacker gains influence over the environment used to launch the Skill, such as a deployment configuration, wra ...[truncated 1509 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require the https scheme before transmitting credentials.
  2. Allowlist openapi.iwencai.com as the default and production destination.
  3. If custom endpoints are a legitimate requirement, maintain an explicit trusted-host allowlist rather than accepting arbitrary URLs.
  4. Reject URLs containing embedded credentials, fragments, unexpected ports, or ambiguous hostname forms.
  5. Normalize and parse the URL with urllib.parse.urlsplit before validation; do not validate using substring or suffix checks alone.
  6. Avoid forwarding the production credential when the configured destination is outside the approved trust boundary.
  7. Fail closed with a clear error when validation fails.
  8. Document that queries are transmitted to the remote service and may contain user-provided information.
  9. Consider isolating endpoint selection from ordinary environment configuration so less-trusted launch contexts cannot silently redirect authenticated traffic.

Example hardening pattern:

python
from urllib.parse import urlsplit

DEFAULT_BASE_URL = "https://openapi.iwencai.com"
ALLOWED_HOSTS = {"openapi.iwencai.com"}

candidate = os.environ.get("IWENCAI_BASE_URL", DEFAULT_BASE_URL).rstrip("/")
parsed = urlsplit(candidate)

if (
    parsed.scheme != "https"
    or parsed.hostname not in ALLOWED_HOSTS
    or parsed.username is not None
    or parsed.password is not None
    or parsed.fragment
    or parsed.port not in (None, 443)
):
    raise RuntimeError("IWENCAI_BASE_URL is not an approved HTTPS endpoint")

BASE_URL = candidate

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cli.py:214
Finding

API Key Accepted Through a Command-Line Argument

Content
View full analysis

Vulnerability Details

File Location: scripts/cli.py, lines 214 and 221–224
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
parser.add_argument("--api-key", default="",    help="API Key(默认从 IWENCAI_API_KEY 环境变量读取)")
python
# 覆盖全局 API_KEY(若命令行传入)
global API_KEY
if args.api_key:
    API_KEY = args.api_key

Technical Analysis

The CLI permits users to provide the bearer API key through --api-key. Command-line arguments are not an appropriate secret-transport mechanism on many platforms because they can be exposed through:

  • Process-listing and system-monitoring utilities.
  • Process accounting or endpoint telemetry.
  • Shell command history.
  • CI/CD execution logs.
  • Wrapper scripts and diagnostic output.
  • Job metadata retained by orchestration platforms.

The environment-variable mechanism already implemented by the Skill is sufficient for its declared functionality, so exposing an additional command-line credential channel is unnecessary and increases the credential's exposure surface.

Environment variables also require careful handling, but they generally avoid routine shell-history and process-argument exposure. A protected credential store or non-echoing interactive prompt would provide stronger handling.

Attack Path

  1. A user invokes the CLI with a command such as:

    bash
    python3 scripts/cli.py --type market --query "example" --api-key SECRET
    
  2. The operating system, shell, automation platform, or monitoring software records or exposes the process arguments.

  3. A local user, administrator, log reader, telemetry operator, or attacker with access to the relevant records retrieves SECRET.

  4. The exposed key is used to issue unauthorized requests against the API within the key's assigned permissions.

Exploitation depends on the victim actually using --api-key ...[truncated 645 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the --api-key command-line option.
  2. Continue supporting IWENCAI_API_KEY while documenting secure environment configuration practices.
  3. For interactive usage, optionally retrieve the key with getpass.getpass() so it is not echoed or placed in shell history.
  4. For managed deployments, use the platform's protected secret store and inject the value only into the process that requires it.
  5. Ensure error messages never print the API key.
  6. If immediate removal would break compatibility, deprecate the option, emit a security warning, and avoid showing secret-bearing examples in documentation.
  7. Rotate any key known to have been supplied in logged command lines.

A safer interface would retain only environment-based loading:

python
API_KEY = os.environ.get("IWENCAI_API_KEY", "")

if not API_KEY:
    print(
        "[Error] IWENCAI_API_KEY is not configured.",
        file=sys.stderr,
    )
    sys.exit(1)
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The CLI builds outbound requests using BASE_URL from the IWENCAI_BASE_URL environment variable without validation, so an attacker who can influence the environment can redirect requests to an arbitrary host. Because the request includes the Bearer API key in the Authorization header, this can exfiltrate credentials and send user queries to an attacker-controlled endpoint; in a skill/agent context, environment variables are part of the trust boundary and should not be treated as safe input.

Content

Scanner excerpt · scripts/cli.py (reported line 69)May include surrounding context.

python
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    req  = urllib.request.Request(url, data=body, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        err_body = e.read().decode("utf-8", errors="replace")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill performs network requests and reads environment variables, but the manifest does not declare any tool scope or permissions boundaries. This can lead to silent access to secrets and outbound data transfer without explicit review, making it harder for a host system or user to understand and constrain what the skill can do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill says it 'must' be used for a very broad set of finance-related queries, which risks unintended invocation for many user requests. Over-broad activation can cause unnecessary external API calls, leakage of sensitive user prompts, and reduced user control over whether third-party services are contacted.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill routes user queries to an external API but does not warn users in the markdown that their prompts may be transmitted to a third-party service. In a finance context, queries may contain trading interests, portfolio details, or other sensitive information, so lack of disclosure increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module docstring presents the skill entirely in Chinese, and the CLI help text later continues in Chinese, which imposes a specific language/locale on users. Under the policy, locale-specific behavior should either offer user choice or clearly justify the constraint as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The argument descriptions, examples, and error messages are all presented only in Chinese. This can violate language/locale policy when the skill does not provide an explicit user choice or state that the skill is intentionally limited to a Chinese-language audience.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.