Back to skill

Security audit

UniFuncs Reader

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it can send URLs and authentication cookies to a third-party API without clear enough warning or scoping.

Review before installing. Use it only for URLs you are comfortable sending to UniFuncs, avoid private/internal URLs, and do not pass browser session cookies unless you understand that they can grant account access and will be exposed through the command line and the remote service.

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
read.py:183
Finding
Authentication Cookies Are Disclosed to a Third-Party Service and Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `read.py:92-94`, `read.py:183-184`, `read.py:192-203`; documented at `SKILL.md:61-63` **Vulnerability Type**: Sensitive credential exposure **Risk Level**: High ### Complete Code Snippet ```python parser.add_argument( "--set-cookie", type=str, help="Set Cookie header value for pages requiring authentication.", ) ``` ```python if args.set_cookie: payload["setCookie"] = args.set_cookie ``` ```python def execute_read(payload: Dict[str, Any], api_key: str) -> Dict[str, Any] | str: """Call UniFuncs Web Reader API and return parsed response.""" json_data = json.dumps(payload).encode("utf-8") headers = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", } req = urllib.request.Request(API_URL, data=json_data, headers=headers, method="POST") try: with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as response: response_data = response.read().decode("utf-8") ``` The corresponding documentation explicitly presents this option: ```text --set-cookie SET_COOKIE Set Cookie header value for pages requiring authentication. ``` ### Technical Analysis The `--set-cookie` option accepts a complete HTTP cookie value through a command-line argument. The implementation places that value in the `setCookie` field of a JSON request and sends it to the fixed third-party endpoint `https://api.unifuncs.com/api/web-reader/read`. This creates two credential-exposure channels: 1. The cookie can be recorded in shell history or exposed to local process-inspection facilities because it is supplied through `argv`. 2. The complete cookie is disclosed to UniFuncs so that its infrastructure can retrieve the authenticated page. Authenticated-page retrieval may legitimately require the remote service to receive a credential, but this behavior is optional and is not required for ordinary publ ...[truncated 1753 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove authenticated-cookie support unless it is essential to the Skill's declared purpose. 2. If the feature is retained, require explicit user confirmation before transmitting credentials to UniFuncs and clearly disclose: - The destination receiving the cookie. - The reason the cookie is required. - Applicable retention and logging behavior. - The risk that the cookie may enable account impersonation. 3. Do not accept secrets directly through command-line arguments. Read them from protected standard input, an operating-system credential store, or a file with restrictive permissions. 4. Encourage use of short-lived, narrowly scoped authentication tokens instead of complete browser cookie headers. 5. Reject broad or unrelated cookie values and transmit only the minimum cookie required for the requested target. 6. Ensure the service redacts cookies from application, proxy, telemetry, and error logs and does not retain them after processing. 7. Never include cookie values in exception messages or diagnostic output. 8. Document how users can invalidate the credential immediately after use. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
read.py:128
Finding
Permissive URL Validation Allows Unsupported and Potentially Sensitive Targets<![CDATA[ ## Vulnerability Details **File Location**: `read.py:128-134` **Vulnerability Type**: Improper URL validation and potential server-side request forgery input **Risk Level**: Low ### Complete Code Snippet ```python def validate_url(url: str) -> bool: """Perform a permissive URL format check.""" try: parsed = urllib.parse.urlparse(url) return bool(parsed.netloc or parsed.path) except Exception: return False ``` ### Technical Analysis The validation only requires the parsed value to contain either a network location or a path. It does not restrict the scheme to the documented HTTP or HTTPS protocols, require a valid hostname, reject embedded credentials, or block localhost, private, link-local, and reserved network destinations. As a result, inputs such as local paths, unusual URI schemes, loopback targets, and private-network addresses can pass validation and be forwarded to the UniFuncs API. The local script does not directly fetch the target URL, which limits direct client-side impact. Any server-side request forgery or local-file access ultimately depends on the remote API's own validation and supported protocols. Nevertheless, the client accepts targets beyond the Skill's declared web-page and document-reading functionality and relies entirely on undocumented server-side protections. ### Attack Path 1. An attacker or untrusted caller supplies a target such as a localhost address, private-network URL, reserved address, or unsupported URI scheme. 2. `validate_url()` accepts the value because it has a nonempty `netloc` or `path`. 3. `build_payload()` inserts the unmodified value into the API request. 4. The client forwards the target to the UniFuncs API. 5. If the remote service lacks equivalent scheme, address, DNS-rebinding, and redirect validation, it may attempt to retrieve an internal or otherwise prohibited resource. 6. Any returned content could then be exposed through the script's standard output. ### ...[truncated 511 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Allow only explicitly supported schemes, preferably `https` and, only if necessary, `http`. 2. Require a syntactically valid hostname and reject URLs containing embedded usernames or passwords. 3. Reject loopback, private, link-local, multicast, unspecified, and reserved IP address ranges. 4. Resolve hostnames and validate all resulting addresses before retrieval. 5. Revalidate every redirect target and protect against DNS rebinding between validation and connection. 6. Reject local paths and unsupported schemes such as `file`, `data`, and custom handlers. 7. Enforce the same restrictions on the UniFuncs server because client-side validation alone cannot secure a remotely accessible API. 8. Return a clear validation error before transmitting a prohibited target. ]]>
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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (8)

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

Critical
Category
Data Flow
Content
req = urllib.request.Request(API_URL, data=json_data, headers=headers, method="POST")

    try:
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT_SECONDS) as response:
            response_data = response.read().decode("utf-8")
            try:
                return json.loads(response_data)
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Missing User Warnings

High
Confidence
97% confidence
Finding
The documentation does not clearly disclose that user-supplied URLs and optional cookies are transmitted to the UniFuncs external API for processing. This is especially dangerous because the `--set-cookie` option could expose session tokens or authenticated content to a third party, leading to privacy breaches, account compromise, or unauthorized data access.

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill makes HTTP requests to an external service but does not declare network capability. In this context, the omission matters because the skill transmits user-provided URLs and potentially cookies/content selection parameters to a third party, which is a real data exposure surface.

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill makes HTTP requests to an external service but does not declare network capability. In this context, the omission matters because the skill transmits user-provided URLs and potentially cookies/content selection parameters to a third party, which is a real data exposure surface.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The skill description is broad enough to trigger on many ordinary requests involving reading or extracting content, which can cause over-invocation of an external-service skill. In context, this increases the chance that users will unknowingly send arbitrary URLs, documents, or even authenticated targets to a third party without realizing the data flow.

External Transmission

Medium
Category
Data Exfiltration
Content
import urllib.request
from typing import Any, Dict

API_URL = "https://api.unifuncs.com/api/web-reader/read"
REQUEST_TIMEOUT_SECONDS = 300
DEFAULT_READ_TIMEOUT_MS = 180000
DEFAULT_EXTRACT_TIMEOUT_MS = 180000
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script forwards a user-supplied target URL and an optional authentication cookie to a remote API for retrieval and extraction, but it provides no explicit warning that these values leave the local environment. This is dangerous because users may supply authenticated or sensitive internal resources, causing session secrets or private document locations to be disclosed to a third-party service.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest frames the skill as a reader/extractor for web pages and documents, but the documentation also requires users to manage an external service credential through an environment variable. While this may be needed for the UniFuncs API integration, credential setup is an additional capability not reflected in the manifest's stated scope.

Static analysis

No suspicious patterns detected.