Back to skill

Security audit

Eyun Watch

Security checks for vulnerabilities and agentic risk

Overview

The skill’s freight-watch purpose is coherent, but it creates an indefinite recurring agent task with shell execution and external notifications, which needs careful review before installation.

Review this before installing in production. Only use it with a trusted Eyun endpoint over HTTPS, validated configuration values, and an approved notification channel. Confirm that operators understand it can create a recurring OpenClaw cron with exec, and define how to list, audit, expire, or remove eyun-watch-poll when no watches remain.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (3)

T06 · System Persistence

Error
Location
SKILL.md:136
Finding

Persistent Scheduled Agent with Shell Execution Capability

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:136-160
Vulnerability Type: Cross-session scheduled-task persistence
Risk Level: High

Vulnerable Code

bash
openclaw cron add \
  --name "eyun-watch-poll" \
  --every "5m" \
  --session isolated \
  --message "Call the Eyun watch results API and notify the user if there are new freight results.

Steps:
1. Run this command:
   curl -s -X GET \"{EYUN_BASE_URL}/api/v1/watch-results/push\" -H \"company-id: {EYUN_COMPANY_ID}\"

2. Parse the JSON response.
   - If 'data' is an empty array: do nothing, output nothing.
   - If 'data' has items: format each item as a freight rate notification (route, carrier, price, ETD) and output the summary.

Output language: Chinese." \
  --tools exec \
  --announce \
  --channel {channel} \
  --to {to}

This behavior is corroborated by the deployment instructions at README.md:48-65, which also create a five-minute recurring task with --tools exec.

Technical Analysis

The skill directs the agent to install an Openclaw cron task that executes every five minutes and is granted access to the general-purpose shell execution tool. The task persists across sessions and continues operating after the conversation that created it has ended.

Individual watch tasks are documented as lasting seven days, but the cron task itself has no expiration, automatic removal procedure, or condition that disables it when no active watches remain. Consequently, a single confirmed watch can establish indefinite recurring agent execution.

Although polling is related to the advertised functionality, the use of a persistent scheduler with unrestricted exec capability creates a durable execution channel with broader privileges and a longer lifetime than an individual watch requires.

Attack Path

  1. A user asks the agent to create a freight-price watch.
  2. The user confirms the watch after reviewing its summary.

...[truncated 1010 chars]

Remediation
View remediation

Remediation Suggestions

  • Prefer authenticated server-side notifications or webhooks instead of installing a local recurring agent.
  • If polling is unavoidable, use a constrained HTTP-only tool rather than granting the cron agent general shell execution through --tools exec.
  • Associate the scheduler with active watch records and automatically remove or disable it when no active watches remain.
  • Set an explicit maximum lifetime consistent with the documented seven-day watch duration.
  • Require separate, explicit user or administrator approval before installing persistent infrastructure.
  • Pin the destination origin and allowed API path so later configuration changes cannot repurpose the scheduler.
  • Add administrative documentation covering task inventory, expiration, revocation, and removal.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:142
Finding

Shell and CLI Argument Injection Through Unvalidated Configuration Interpolation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:142-184
Vulnerability Type: Command and argument injection
Risk Level: High

Vulnerable Code

The cron command embeds configuration values in executable command text and passes other values as unquoted CLI arguments:

bash
openclaw cron add \
  --name "eyun-watch-poll" \
  --every "5m" \
  --session isolated \
  --message "Call the Eyun watch results API and notify the user if there are new freight results.

Steps:
1. Run this command:
   curl -s -X GET \"{EYUN_BASE_URL}/api/v1/watch-results/push\" -H \"company-id: {EYUN_COMPANY_ID}\"

2. Parse the JSON response.
   - If 'data' is an empty array: do nothing, output nothing.
   - If 'data' has items: format each item as a freight rate notification (route, carrier, price, ETD) and output the summary.

Output language: Chinese." \
  --tools exec \
  --announce \
  --channel {channel} \
  --to {to}

The watch-creation request similarly interpolates configuration values into a shell command:

bash
curl -s -X POST "{EYUN_BASE_URL}/api/v1/watch-tasks" \
  -H "Content-Type: application/json" \
  -H "company-id: {EYUN_COMPANY_ID}" \
  -d '{
    "pol": "<起运港代码>",
    "pol_name": "<起运港名称或 null>",
    "pod": "<目的港代码>",
    "pod_name": "<目的港名称或 null>",
    "container_type": "<箱型代码或 null>",
    "carrier": "<船公司或 null>",
    "etd": "<船期 YYYY-MM-DD 或 null>",
    "target_price": <目标价格数字或 null>,
    "currency": "USD"
  }'

Technical Analysis

The skill instructs the agent to retrieve EYUN_BASE_URL, EYUN_COMPANY_ID, channel, and to from configuration and substitute them directly into shell commands. It does not define validation rules, a safe escaping procedure, or a structured process-execution API.

The channel and to substitutions are unquoted. Values containing whitespace or leading option syntax can ...[truncated 1990 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not construct shell command strings by interpolating configuration values.
  • Invoke HTTP and Openclaw operations through structured APIs that accept an argument array and do not invoke a shell.
  • Require EYUN_BASE_URL to parse as an HTTPS URL whose hostname and port match an explicit allowlist.
  • Require EYUN_COMPANY_ID to match its documented numeric format.
  • Restrict channel to a fixed enumeration of supported channel identifiers.
  • Validate to against the selected channel's destination format and reject whitespace, control characters, and option-like values.
  • If shell execution cannot be removed, apply context-aware escaping using a trusted library rather than manual quoting.
  • Build request bodies with a JSON serializer so user values cannot break JSON or shell quoting.
  • Review existing eyun-watch-poll tasks and recreate them after validation to remove any previously stored injected instructions.

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:14
Finding

Tenant Identifier and API Traffic Permitted Over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: README.md:14-24
Vulnerability Type: Insecure transport of tenant-scoped API data
Risk Level: Medium

Vulnerable Code

The documented deployment configuration explicitly uses a plaintext HTTP endpoint:

json
{
  "skills": {
    "entries": {
      "eyun_watch": {
        "enabled": true,
        "env": {
          "EYUN_BASE_URL": "http://<eyun-server-ip>:8010",
          "EYUN_COMPANY_ID": "<企业 ID 数字>"
        }
      }
    }
  }
}

The identifier is subsequently transmitted in recurring API requests at README.md:56:

bash
curl -s -X GET \"$EYUN_BASE_URL/api/v1/watch-results/push\" -H \"company-id: $EYUN_COMPANY_ID\"

It is also transmitted by the task-creation request at SKILL.md:181-184:

bash
curl -s -X POST "{EYUN_BASE_URL}/api/v1/watch-tasks" \
  -H "Content-Type: application/json" \
  -H "company-id: {EYUN_COMPANY_ID}"

Technical Analysis

The deployment example permits or encourages an http:// service URL. Both task creation and recurring result polling transmit a company identifier and freight-related data without transport encryption or server authentication.

The documentation does not require TLS, certificate validation, endpoint pinning, or a separate authenticated credential. If the company-id header is used for authorization rather than identification alone, interception may enable tenant impersonation. Even if it is not an authorization secret, plaintext responses and requests remain vulnerable to observation and modification.

Because polling occurs every five minutes, exposure is recurring rather than limited to the initial watch-creation request.

Attack Path

  1. An operator follows the documented configuration and sets EYUN_BASE_URL to an HTTP endpoint.
  2. The skill sends the company identifier and watch-task details over the network.
  3. A network-positioned atta ...[truncated 876 chars]
Remediation
View remediation

Remediation Suggestions

  • Require https:// for EYUN_BASE_URL and reject plaintext HTTP during configuration validation.
  • Enable normal certificate-chain and hostname verification; do not use insecure TLS flags.
  • Use a revocable, narrowly scoped authentication token instead of relying on a company identifier as an authorization mechanism.
  • Keep the company ID as a non-secret tenant selector and enforce authorization independently on the server.
  • Consider mutual TLS or signed requests for deployments across untrusted networks.
  • Update all deployment examples to use a valid HTTPS origin.
  • Document secure certificate provisioning for private-network installations.
  • Rotate any tenant credentials or identifiers that may previously have traversed untrusted plaintext networks.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation directs operators to set up continuous polling and automatic push notifications to Telegram without clearly warning that freight result data will be regularly transmitted to an external messaging platform. In a business context, routing, pricing, ETD, and carrier information may be commercially sensitive, so silent or insufficiently disclosed onward transmission can cause confidentiality and privacy issues.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README instructs operators to grant the cron workflow --tools exec, allowing shell execution for a task whose functional goal is only to perform periodic HTTP GET requests. In an agent setting, broad shell capability materially increases the blast radius if the prompt, environment variables, or upstream response handling are abused, because the scheduled task can execute arbitrary commands rather than being constrained to a narrow network action.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trigger phrases are broad enough to match ordinary conversation about alerts or notifications, increasing the chance the skill activates when the user did not intend to create a persistent watch workflow. In this skill, accidental activation is more serious because later steps can register long-lived automation and send future outbound notifications. Overbroad triggering therefore raises the risk of unauthorized or surprising side effects.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill’s declared purpose is to create price-watch tasks and notify users, but it also provisions and manages a persistent background cron job. That expands the capability surface from a one-time task creation flow into ongoing autonomous execution, which can continue making network calls and sending notifications after the initial interaction. Because this persistence is not clearly scoped in the manifest or prominently disclosed to the user, it creates a meaningful risk of surprise automation and misuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The workflow creates or reuses a persistent cron job and uses stored push-target configuration to send future notifications, but the skill description does not clearly warn the user about those durable side effects. This omission undermines informed consent: a user may think they are creating a simple one-time alert, while the skill is actually enabling autonomous polling and message delivery to a configured destination. In context, the hidden persistence and implicit use of stored recipients make this substantially more dangerous.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The cron job performs periodic external transmission by calling a remote watch-results API and then emits notifications when data is present. External transmission is expected for this skill’s business purpose, but here it occurs from a persistent autonomous job and is coupled with stored notification routing, which increases the risk of data being sent or surfaced beyond the user’s immediate awareness. The danger comes less from the existence of the network call itself and more from the ongoing unattended execution and disclosure model around it.

Content

Scanner excerpt · SKILL.md (reported line 150)May include surrounding context.

md
Steps:
1. Run this command:
   curl -s -X GET \"{EYUN_BASE_URL}/api/v1/watch-results/push\" -H \"company-id: {EYUN_COMPANY_ID}\"

2. Parse the JSON response.
   - If 'data' is an empty array: do nothing, output nothing.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The manifest says the skill creates watch tasks and lets users receive IM notifications when rates are available. In the README, the notification behavior is actually achieved by separately registering an Openclaw cron job with announce/channel settings, meaning the skill alone does not deliver notifications without extra platform-level setup.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The instruction string explicitly sets 'Output language: Chinese.' This forces a specific language choice and does not offer user selection or document a justified locale restriction, which conflicts with the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The skill instructs the agent to read broad runtime configuration including notification routing fields such as channel and recipient target, not just the API base URL and company identifier needed to create a watch task. Access to stored routing configuration broadens the skill’s reach into messaging destinations and can enable notifications to be sent without the user explicitly specifying or reviewing where they will go. In a skill that appears user-facing and transactional, that is more access than the core function strictly requires.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The embedded natural-language instruction explicitly says “Output language: Chinese.” This forces a specific language choice without opt-in or explanation, which is a locale-policy issue under the rule.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.