Back to skill

Security audit

ModelReady

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but its default server settings can expose an unauthenticated model API to the network without clear warning.

Review before installing. Use this only if you understand that it can start a long-running vLLM server and, by default, may listen on all network interfaces. Prefer binding to 127.0.0.1, avoid sending sensitive prompts to remote or untrusted hosts, and stop the server when finished.

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
tool/modelready.sh:42
Finding
Unauthenticated model API exposed on all network interfaces by default<![CDATA[ ## Vulnerability Details **File Location**: `tool/modelready.sh`, lines 42 and 151-180 **Vulnerability Type**: Unauthenticated network service exposure **Risk Level**: High ### Vulnerable Code ```bash DEFAULT_HOST="${DEFAULT_HOST:-0.0.0.0}" ``` ```bash # build args ARGS=(--model "$REPO" --host "$HOST" --port "$PORT" --tensor-parallel-size "$TP" --dtype "$DTYPE") if [[ -n "$NAME" ]]; then ARGS+=(--served-model-name "$NAME") fi if [[ -n "$MAX_NUM_SEQS" ]]; then ARGS+=(--max-num-seqs "$MAX_NUM_SEQS") fi if [[ "$AUTO_TOOL" == "1" ]]; then ARGS+=(--enable-auto-tool-choice) fi if [[ -n "$TOOL_PARSER" ]]; then ARGS+=(--tool-call-parser "$TOOL_PARSER") fi # OPTIONAL: passthrough extra="--foo bar --baz 1" EXTRA="${KV[extra]:-}" if [[ -n "$EXTRA" ]]; then # shellcheck disable=SC2206 EXTRA_ARR=($EXTRA) ARGS+=("${EXTRA_ARR[@]}") fi # start server nohup python3 -m vllm.entrypoints.openai.api_server \ "${ARGS[@]}" \ >"$LOG_FILE" 2>&1 & ``` ### Technical Analysis The default bind address is `0.0.0.0`, which causes vLLM to listen on every available network interface rather than only the loopback interface. The constructed server command does not configure an API key, authentication layer, TLS, or any client access restriction. Consequently, the documented `start` operation creates an OpenAI-compatible HTTP API that may be reachable by other systems on the local network and, depending on firewall and routing configuration, by external systems. This behavior conflicts with the documentation's characterization of the model as being served locally. The exposure does not require command injection or code execution within the shell script. An attacker only needs network connectivity to the configured port and can interact directly with vLLM's API. ### Attack Path 1. A user invokes the documented model start command without specifying a safer bind address. 2. `DEFAULT_HOST` resolves to `0.0.0.0`. 3. The script launches vLLM with `--host 0.0. ...[truncated 918 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Change the default bind address to loopback: ```bash DEFAULT_HOST="${DEFAULT_HOST:-127.0.0.1}" ``` 2. Require explicit user confirmation before allowing `0.0.0.0` or another non-loopback address. 3. When remote access is enabled, configure vLLM with a strong API key and ensure all clients authenticate. 4. Place remotely accessible deployments behind a TLS-enabled reverse proxy with authentication, request limits, and access logging. 5. Apply host firewall rules restricting access to trusted source addresses. 6. Display a prominent warning containing the effective bind address whenever a non-loopback server is started. 7. Update `SKILL.md` to distinguish loopback-only operation from deliberate network exposure. 8. Add startup validation that refuses unauthenticated non-loopback binding unless an explicit unsafe override is supplied. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
tool/modelready.sh:77
Finding
Unrestricted cleartext transmission of chat content to a configurable host<![CDATA[ ## Vulnerability Details **File Location**: `tool/modelready.sh`, lines 77-87 and 211-248 **Vulnerability Type**: Unrestricted outbound request and plaintext sensitive-data transmission **Risk Level**: Medium ### Vulnerable Code ```bash set_ip() { local ip="${KV[ip]:-}" if [[ -z "$ip" ]]; then echo "Missing ip=..." echo "e.g. $0 set_ip ip=0.0.0.0" exit 1 fi DEFAULT_HOST="$ip" save_defaults echo "OK default_host=$DEFAULT_HOST" } ``` ```bash chat() { TEXT="${KV[text]:-}" if [[ -z "$TEXT" ]]; then echo "Missing text=..." exit 1 fi MODEL="${KV[model]:-moderation}" TEMP="${KV[temp]:-0}" MAX_TOKENS="${KV[max_tokens]:-256}" CHAT_PORT="${KV[port]:-$DEFAULT_PORT}" CHAT_HOST="${KV[host]:-$DEFAULT_HOST}" # for client, 0.0.0.0 must be resolved to real IP/loopback if [[ "$CHAT_HOST" == "0.0.0.0" ]]; then CHAT_HOST="$(get_ip)" fi URL="http://${CHAT_HOST}:${CHAT_PORT}/v1/chat/completions" CHAT_TEXT="$TEXT" CHAT_MODEL="$MODEL" CHAT_TEMP="$TEMP" CHAT_MAX_TOKENS="$MAX_TOKENS" CHAT_URL="$URL" \ python3 - <<'PY' import json, os, re, sys, urllib.request, urllib.error url = os.environ["CHAT_URL"] payload = { "model": os.environ.get("CHAT_MODEL", "moderation"), "messages": [{"role": "user", "content": os.environ.get("CHAT_TEXT", "")}], "temperature": float(os.environ.get("CHAT_TEMP", "0")), "max_tokens": int(os.environ.get("CHAT_MAX_TOKENS", "256")), } print(url, file=sys.stderr) req = urllib.request.Request( url, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers={"Content-Type": "application/json"}, ) try: import urllib.request opener = urllib.request.build_opener( urllib.request.ProxyHandler({}) ) with opener.open(req, timeout=300) as resp: data = json.load(resp) ``` ### Technical Analysis The `set_ip` command persists an arbitrary string as the default host without validating whether it is a loopback address, trusted ...[truncated 2439 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict ordinary chat destinations to loopback addresses such as `127.0.0.1` and `::1`. 2. Validate hosts using proper IP-address and hostname parsing rather than string pattern matching. 3. Reject unspecified, multicast, link-local, metadata-service, and private-network destinations unless an explicit trusted remote mode is enabled. 4. Maintain an allowlist of approved model server destinations when remote operation is required. 5. Require HTTPS for non-loopback destinations and retain normal certificate and hostname verification. 6. Display the resolved destination and request explicit confirmation before transmitting chat content remotely. 7. Resolve hostnames and validate all resulting addresses to reduce DNS rebinding risks. 8. Add connection and response-size limits in addition to the existing request timeout. 9. Clearly document that the `text` value is transmitted to the selected host and may contain sensitive information. 10. Avoid persisting unrestricted remote hosts as defaults, or store only destinations explicitly approved by the user. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares operational capabilities via metadata requirements and documented behavior that imply shell execution, environment-variable use, and network access, but it does not constrain those capabilities with an explicit tool scope such as permissions or allowed-tools. In an agent setting, that increases the chance the skill can invoke broader-than-necessary actions, including launching services and making networked requests, without clear policy boundaries.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation instructs users to start a model server, set host/port, and expose an OpenAI-compatible endpoint, but it does not warn that this alters local system and network state or may bind a service reachable by other processes or hosts. In practice, users may unintentionally expose an inference endpoint, consume significant local resources, or interact with untrusted model artifacts without understanding the security implications.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script persists a default bind host and defaults to 0.0.0.0, which exposes the vLLM API on all network interfaces rather than localhost only. In the context of a chat helper skill, this broadens attack surface and can unintentionally make a local model service reachable by other hosts on the network.

Session Persistence

Medium
Category
Rogue Agent
Content
fi

  # start server
  nohup python3 -m vllm.entrypoints.openai.api_server \
    "${ARGS[@]}" \
    >"$LOG_FILE" 2>&1 &
Confidence
65% confidence
Finding
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.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The script prints the final model response with a fixed Chinese prefix (`你的模型说:`), which imposes a specific language regardless of the user's locale or preferences. This is a natural-language policy issue because the skill does not offer any language selection or document a justified locale constraint.

Vague Triggers

Low
Confidence
84% confidence
Finding
This markdown file says to use the skill to 'start using a local or Hugging Face model instantly' and 'test or interact with a model directly from chat' without defining narrower trigger phrases, exclusions, or negative examples. The invocation scope is broad enough that many generic model-related requests could match, increasing the chance of unintended activation.

Static analysis

No suspicious patterns detected.