Back to skill

Security audit

Uno CLI

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real tool-gateway skill, but its executable behavior depends on mutable external PyPI code and its Chinese instructions weaken the promised approval-before-call safety model.

Install only if you are comfortable with a broad external tool gateway that can access connected services and spend credits. Pin and verify the uno-cli package version before use, require dry-run preview and explicit approval for every real call regardless of language, and be especially careful with logout, disconnect, key deletion, purchases, posts, sends, writes, and any personal-app integrations.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T08 · Insecure Dependencies

Error
Location
SKILL.md:31
Finding
Mutable and Unreviewed PyPI Dependency Executes with User Privileges<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:31-40`; `bin/uno.py:47-64` **Vulnerability Type**: Supply-chain risk through an incompletely pinned runtime dependency **Risk Level**: High ### Complete Code Snippet From `SKILL.md`: ```markdown - The [`uno-cli`](https://pypi.org/project/uno-cli/) PyPI package, **≥ 1.0.2** (MIT, stdlib-only, no transitive deps) — 1.0.1 introduced unconditional stdout secret-stripping; 1.0.2 adds `call --dry-run` for credential-free preview of a planned invocation The bundled `bin/uno.py` is a thin launcher that forwards to the `uno-cli` package. This means upgrades land via `pip install --upgrade uno-cli` without shipping a new skill release. CLI path (relative to this file): `bin/uno.py` ## Step 0: Install the Uno CLI (one-time) ```bash python3 -m pip install --user --upgrade 'uno-cli>=1.0.2' ``` ``` From `bin/uno.py`: ```python def _report_missing(): sys.stdout.write( json.dumps( { "error": "uno-cli not installed", "hint": ( "Install the Uno CLI first: " "python3 -m pip install --user --upgrade 'uno-cli>=1.0.0'" ), "install_url": "https://pypi.org/project/uno-cli/", }, ensure_ascii=False, ) + "\n" ) sys.exit(2) try: from uno_cli.cli import main except ModuleNotFoundError: _report_missing() # Attribution tag only — no scope restriction for the full-gateway skill. os.environ.setdefault("UNO_CALLER_SKILL", "uno-cli") ``` ### Technical Analysis The bundled script does not implement the advertised CLI functionality. It imports and executes `uno_cli.cli.main` from a separately installed PyPI package. Consequently, authentication, credential-file access, secret filtering, network communication, and remote tool invocation are all performed by code absent from the audited artifact. The installation command combines `--upgrade` ...[truncated 1940 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `uno-cli` to one specifically reviewed version instead of using a lower bound: ```bash python3 -m pip install --user 'uno-cli==REVIEWED_VERSION' ``` 2. Remove `--upgrade` from automated or agent-directed installation instructions. 3. Enforce package integrity using a reviewed wheel hash and `pip --require-hashes`. 4. Vendor the reviewed CLI implementation into the Skill, or include its complete source so credential and network behavior can be audited with the Skill. 5. Use a lock file or similarly reproducible dependency manifest. 6. Change every installation hint to the same reviewed version. In particular, do not permit version `1.0.0` when the declared protections require at least `1.0.2`. 7. Verify the installed package version before importing it and fail closed if it differs from the reviewed version. 8. Perform dependency provenance and release-signature verification where supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
skill-zh.md:151
Finding
Chinese Instructions Omit Mandatory Dry-Run and Explicit Per-Call Approval<![CDATA[ ## Vulnerability Details **File Location**: `skill-zh.md:151-158,211-224`; conflicting control in `SKILL.md:181-203,263-277` **Vulnerability Type**: Inconsistent safety workflow permitting unapproved remote calls **Risk Level**: Medium ### Complete Code Snippet The direct-call example in `skill-zh.md` is: ```bash python bin/uno.py call <tool_slug> --args '{"city":"Beijing"}' ``` The corresponding workflow permits calls, retries after authorization, and post-call ratings but contains no mandatory dry-run and approval step. By contrast, `SKILL.md` defines the required safety sequence: ```markdown **Step 1 — always preview first with `--dry-run`** (zero network, zero credential read, zero credits): ```bash python bin/uno.py call --dry-run weather-free.weather_now --args '{"city":"Beijing"}' ``` Show this JSON to the user and wait for explicit approval. **Step 2 — after the user approves, re-run without `--dry-run`**: ```bash python bin/uno.py call weather-free.weather_now --args '{"city":"Beijing"}' ``` ``` It also states: ```markdown 3. **Dry-run before real call** — always run `call --dry-run` first and show the preview JSON (tool + arguments) to the user; only proceed to a real `call` after explicit user approval ``` ### Technical Analysis The English specification claims that every real invocation is preceded by a credential-free dry-run, disclosure of the selected tool and arguments, and explicit human approval. The Chinese instructions do not preserve this control. They provide a direct real-call example and omit the approval requirement from the agent workflow. This is a security-relevant inconsistency because Skill instructions may be selected according to the user's language. An agent following the Chinese document can treat the direct invocation as the expected workflow and transmit arguments to a remote provider immediately. The issue is particularly significant because the gateway advertises broad integrations, including mail, ...[truncated 1786 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make the Chinese and English instructions enforce the same sequence: - Search for one specific tool. - Run `call --dry-run`. - Display the exact tool name and complete arguments. - Wait for explicit user approval. - Perform one real call only after approval. 2. Replace every direct-call example in `skill-zh.md` with a dry-run example followed by a separately documented approved real call. 3. Add an explicit workflow rule prohibiting real calls before approval. 4. Require renewed approval after OAuth authorization if the real call has not yet been approved. 5. Require separate confirmation before retrying any potentially non-idempotent operation. 6. Make ratings opt-in rather than automatically submitting them after successful calls. 7. Add heightened confirmation for write, send, delete, purchase, booking, financial, and account-management operations. 8. Maintain one canonical safety policy and automatically validate translated documentation against it to prevent future divergence. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill metadata promises a constrained search→dry-run→user-confirmed single-call workflow, but the body instructs agents to directly invoke tools and even submit ratings afterward. That mismatch can cause agents to perform external actions or secondary side effects without the explicit preview and approval boundary users were told to expect.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill exposes credential lifecycle, API key management, logout, disconnect, and key deletion capabilities that exceed the stated purpose of a single user-approved tool invocation. Expanding scope in this way increases the chance an agent triggers account-altering or availability-impacting actions that the user did not intend when invoking a narrow lookup tool.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The description encourages use of many external tools and personal app integrations but does not clearly warn that user prompts, parameters, and retrieved data may be transmitted to third-party services. This can lead to privacy and data-handling surprises, especially when agents route user content to external providers.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The documented logout commands can clear local credentials for one or all accounts, yet they are presented without a prominent caution about service disruption and session loss. An agent or user following the instructions may unintentionally invalidate local access and break subsequent workflows.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
API key deletion is a destructive action with potentially broad operational impact, but the documentation does not clearly warn that deleting a key may irreversibly break existing automations or integrations using it. In an agent setting, insufficiently signposted destructive commands increase the risk of accidental denial of service to dependent workflows.

Credential Access

High
Category
Privilege Escalation
Content
1. `login --start` requests a device code from Uno server
2. Show `verification_uri_complete` to the user. The page is `/device` on agentools.uno — they sign in on the website if needed, then Authorize. **Do not `--poll` in the same turn.**
3. After authorization, `login --poll` retrieves an **API key** (`uno_…`) and writes it to `~/.uno/credentials.json`
4. `--poll` waits **10 minutes** by default. The device code is valid **30 minutes**. If poll times out, re-run `--poll` with the **same** `device_code`
5. Server-side keys do **not** expire. Re-login only when: new machine / ephemeral `$HOME`; `logout` (local wipe only); key deleted in the dashboard / `keys delete`; user disabled; a stale `UNO_API_KEY` overrides a good file
6. A tool returning `auth_required` is that **server's** OAuth/key, not the Uno key
Confidence
84% confidence
Finding
The skill explicitly describes storing a long-lived API key in `~/.uno/credentials.json` and also tells agents/CI that workflows needing the real value should read the 0600 credentials file directly. Even with restrictive file permissions and stdout masking, any skill or process running as the same user could potentially access that file, making it a sensitive local secret target if the agent ecosystem is not strongly isolated.

Static analysis

No suspicious patterns detected.