Back to skill

Security audit

Huangxianshi Divination

Security checks for vulnerabilities and agentic risk

Overview

The main divination skill is mostly local and purpose-aligned, but it ships an undocumented sunrise helper that contacts a third party over plaintext HTTP and can wait before running a draw.

Review this before installing. The ordinary draw/explain flow is a local Chinese divination CLI that saves the last draw, but the package also contains an undocumented sunrise script. Avoid running that helper unless you accept the wttr.in request, hardcoded Shanghai timing, and possible long wait; the publisher should document it, use HTTPS, validate responses, or remove it.

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/draw_at_sunrise.sh:8
Finding

Unvalidated Plaintext Network Response Used in Bash Arithmetic

Content
View full analysis

Vulnerability Details

File Location: scripts/draw_at_sunrise.sh, lines 8-26
Vulnerability Type: Command injection through untrusted arithmetic input and insecure plaintext transport
Risk Level: Medium

bash
# Retrieve the Shanghai sunrise time
SUNRISE=$(curl -s "wttr.in/Shanghai?format=%S" 2>/dev/null)
if [ -z "$SUNRISE" ]; then
    echo "Failed to retrieve sunrise time; using default 6:06"
    SUNRISE="06:06:04"
fi

# Extract hour and minute
HOUR=$(echo "$SUNRISE" | cut -d: -f1)
MIN=$(echo "$SUNRISE" | cut -d: -f2)

echo "Today's Shanghai sunrise: $HOUR:$MIN"

# Calculate waiting time
CURRENT_HOUR=$(date +%H)
CURRENT_MIN=$(date +%M)

# Convert to total minutes
CURRENT_TOTAL=$((10#$CURRENT_HOUR * 60 + 10#$CURRENT_MIN))
SUNRISE_TOTAL=$((10#$HOUR * 60 + 10#$MIN))

Technical Analysis

The script retrieves data from wttr.in without explicitly using HTTPS. Curl therefore interprets the endpoint as plaintext HTTP. An attacker capable of intercepting the network connection, or an attacker controlling the remote endpoint, can modify the sunrise response.

The response is split into HOUR and MIN fields with cut, but neither field is validated as a decimal value within the permitted time ranges. Both values are subsequently embedded in a Bash arithmetic expression.

Bash arithmetic evaluation is not equivalent to strict integer parsing. Arithmetic expressions support variables, operators, and recursively evaluated expression constructs. Allowing attacker-controlled text to enter an arithmetic context can therefore cause unintended expression evaluation and, with an appropriately crafted Bash expression, potentially trigger command execution. At minimum, malformed input can cause arithmetic errors and terminate or disrupt the script.

The fallback only handles an empty response. It does not protect against nonempty malicious, malformed, redirected, or unexpected server responses.

...[truncated 1493 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require encrypted transport and fail safely:

    bash
    SUNRISE=$(curl --fail --silent --show-error \
        --max-time 10 \
        "https://wttr.in/Shanghai?format=%S") || {
        SUNRISE="06:06:04"
    }
    
  2. Validate the complete response before extracting or evaluating any fields:

    bash
    if [[ "$SUNRISE" =~ ^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$ ]]; then
        HOUR="${BASH_REMATCH[1]}"
        MIN="${BASH_REMATCH[2]}"
    else
        HOUR=6
        MIN=6
    fi
    
  3. Normalize validated values using strict decimal conversion before arithmetic. Never place arbitrary remote text directly into a Bash arithmetic expression.

  4. Set defensive shell options such as set -euo pipefail, while ensuring network and validation failures are handled through an explicit safe fallback.

  5. Consider replacing the shell parsing logic with a language that offers strict integer conversion and range checking.

  6. Document the external network request and the optional sunrise helper in SKILL.md so operators can assess the privacy and trust implications before executing it.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The core domain is related to lot drawing, so the final invoked action is adjacent to the declared purpose. However, this code chunk does more than the description states: it makes an external network request to wttr.in to obtain sunrise time, computes a delay, sleeps until that time, and then runs a specific 'draw-ritual' command automatically. The declared description emphasizes user-triggered actions like drawing or interpreting a lot when the user says certain phrases, and declares no permissions. The sunrise-based scheduling and external HTTP access are undeclared capabilities and represent a materially different trigger/operation pattern from the stated on-demand user interaction.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes shell commands (python3 ...) and references file-based data, but declares no permissions or allowed-tools scope. That creates an unnecessarily broad execution surface where the runtime may grant more capability than intended, increasing the risk of command execution or file access beyond the divination use case.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Broad trigger phrases like “聊签” or “解签” can fire in ordinary conversation, causing the skill to run when the user did not clearly intend it. In an agent environment with shell-backed actions, accidental activation can lead to unnecessary command execution, confusion, and unintended state changes such as drawing a 'previous lot' context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language comments and the wttr.in request explicitly fix behavior to Shanghai sunrise time. This imposes a specific locale on all users without opt-in or justification, which matches the language/locale policy violation category.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script expands the skill’s behavior beyond simple divination by making an external network request and performing time-based waiting/scheduling. This introduces unnecessary external dependency, nondeterministic execution, and potential privacy/availability issues that are not disclosed by the skill description.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script performs an outbound request to wttr.in solely to obtain sunrise data, even though this is not necessary for the core divination function. Any unsolicited external request leaks usage metadata and creates a supply-chain/dependency surface where a remote service can influence behavior or fail unexpectedly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Querying wttr.in with a location string sends contextual data to a third party without user notice. Even though the location is hard-coded rather than user-derived, the request still reveals that this skill is being run, when it is run, and for what locale, which is an avoidable privacy leak.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code defines the tool description, help text, errors, and user-facing outputs entirely in Chinese, including the accepted aspect keywords, without any opt-in or alternative locale support. Under the policy for natural-language violations, forcing a specific language without user choice is a reportable issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
71% confidence
Finding

The file consists entirely of Chinese titles, poems, stories, and comments, with no indication that the skill is region-specific or that users can opt into this locale. Under the stated policy, forcing a specific language without opt-in can be a natural-language policy violation when no justification is documented.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The trigger documentation is inconsistent: metadata lists one set of phrases while the body lists a slightly different set and also auto-draws when a user asks to explain without prior context. Ambiguous activation rules can cause unpredictable behavior, making it harder to reason about when shell-backed commands will execute and increasing the chance of unintended invocation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.