Back to skill

Security audit

Make PDF safe

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent and disclosed as cloud PDF processing, but it needs Review because an unvalidated endpoint override could send both PDFs and the API key to an unintended server.

Review this before installing. Use it only for PDFs you are comfortable sending to the Cross-Service-Solutions API, and avoid confidential or regulated documents unless that provider is approved for your use case. Prefer SOLUTIONS_API_KEY over --api-key, do not set --base-url or SOLUTIONS_BASE_URL unless you fully trust the exact HTTPS endpoint, and ask the publisher to remove or strictly validate endpoint overrides, add explicit upload confirmation, and pin dependencies.

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
scripts/make-pdf-safe.py:187
Finding
Arbitrary API Endpoint Override Exposes PDF Content and Bearer Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/make-pdf-safe.py:30`, `scripts/make-pdf-safe.py:35`, `scripts/make-pdf-safe.py:57-61`, `scripts/make-pdf-safe.py:79-83`, and `scripts/make-pdf-safe.py:187-189` **Vulnerability Type**: Unrestricted destination override for sensitive network requests **Risk Level**: High ### Vulnerable Code ```python DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions" CREATE_PATH = "/api/41" def make_headers(api_key: str) -> Dict[str, str]: return {"Authorization": f"Bearer {api_key}"} ``` ```python url = base_url.rstrip("/") + CREATE_PATH headers = make_headers(api_key) with open(pdf_path, "rb") as f: files = {"file": (os.path.basename(pdf_path), f, "application/pdf")} resp = requests.post(url, headers=headers, files=files, timeout=timeout_s) ``` ```python url = base_url.rstrip("/") + f"/api/{job_id}" headers = make_headers(api_key) resp = requests.get(url, headers=headers, timeout=timeout_s) ``` ```python ap.add_argument( "--base-url", default=os.getenv("SOLUTIONS_BASE_URL", DEFAULT_BASE_URL), help="Base URL override", ) ``` ### Technical Analysis The script permits the API destination to be overridden through either the `--base-url` argument or the `SOLUTIONS_BASE_URL` environment variable. It does not validate the URL scheme, hostname, port, or path before attaching the Bearer credential and uploading the complete PDF. The declared functionality only requires communication with the documented Solutions API host. Allowing an unrestricted destination therefore exceeds the minimum network privilege necessary for the Skill. An attacker who can influence command arguments, environment variables, a wrapper script, or deployment configuration can redirect requests to an attacker-controlled endpoint. That endpoint receives: - The complete PDF document in a multipart upload. - The Solutions API Bearer credential in the `Authorization` header. - Subsequen ...[truncated 1579 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` and `SOLUTIONS_BASE_URL` if alternate service endpoints are not essential. 2. If endpoint configuration is required, parse the URL and enforce: - The `https` scheme. - An exact allowlisted hostname. - The expected port. - A controlled path prefix. - No embedded username or password. 3. Reject IP literals, loopback addresses, link-local addresses, and private-network destinations unless explicitly required. 4. Disable automatic redirects or validate every redirect target before forwarding the Authorization header. 5. Never forward credentials across origins. 6. Separate endpoint selection from credential use so credentials are issued only to a trusted, configured service identity. 7. Clearly notify users before uploading a document to a third party and identify the exact destination. 8. Add automated tests proving that HTTP URLs, unapproved hosts, deceptive subdomains, and cross-origin redirects are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/make-pdf-safe.py:185
Finding
API Key Can Be Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/make-pdf-safe.py:13`, `scripts/make-pdf-safe.py:185`, and `README.md:36-39` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python Usage: python scripts/make_pdf_safe.py --pdf "/path/to/file.pdf" --api-key "..." ``` ```python ap.add_argument("--api-key", default=os.getenv("SOLUTIONS_API_KEY", ""), help="Solutions API key (Bearer token)") ``` The README recommends the same invocation pattern: ```bash python scripts/make_pdf_safe.py \ --pdf "/path/to/file.pdf" \ --api-key "$SOLUTIONS_API_KEY" ``` ### Technical Analysis The script accepts the Bearer credential through `--api-key`, and the documented example expands an environment variable directly into that argument. After shell expansion, the secret becomes part of the process argument vector. Depending on the operating system and execution environment, command-line arguments may be available through: - Process inspection utilities. - `/proc` process metadata. - Shell history when a literal key is supplied. - CI/CD job metadata and command tracing. - Process accounting, monitoring, audit, or orchestration logs. - Wrapper scripts that record executed commands. This behavior conflicts with the Skill's stated rule that the API key must never be echoed or logged. Although use of `SOLUTIONS_API_KEY` without the argument is supported, the insecure argument mechanism remains available and is explicitly demonstrated. ### Attack Path 1. A user follows the documented example or supplies a literal credential with `--api-key`. 2. The shell expands the value into the process argument vector. 3. A local user, monitoring agent, CI system, or command-logging wrapper observes or records the process arguments. 4. The observer extracts the Bearer credential. 5. The credential is reused against the Solutions API within the authorization scope assigned to that key. ### Impact A ...[truncated 483 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--api-key` command-line option or mark it as deprecated and reject its use in security-sensitive deployments. 2. Read the credential from a protected environment variable, operating-system credential store, secret manager, or restricted file descriptor. 3. For interactive use, obtain the key with a non-echoing prompt such as `getpass.getpass()`. 4. Update the README and script docstring so examples do not place credentials in command-line arguments. 5. Ensure CI/CD environments inject the credential through a masked secret mechanism and disable command tracing around secret handling. 6. Avoid printing, logging, serializing, or including the credential in exception messages. 7. Document credential rotation procedures and advise users to rotate any key previously exposed through process or execution logs. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The code has active network capability via requests.post and requests.get, yet the finding indicates that network use is not covered by declared permissions. In an agent skill, undeclared network access is dangerous because it enables silent transmission of user files and metadata to remote systems outside expected policy enforcement.

Lp1

High
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The code has active network capability via requests.post and requests.get, yet the finding indicates that network use is not covered by declared permissions. In an agent skill, undeclared network access is dangerous because it enables silent transmission of user files and metadata to remote systems outside expected policy enforcement.

External Transmission

Medium
Category
Data Exfiltration
Content
## How it works
1) Upload PDF to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/41`
2) Poll:
   `GET  https://api.xss-cross-service-solutions.com/solutions/solutions/api/<job_id>`
3) Return `output.files[0].path` as the download URL
Confidence
96% confidence
Finding
The skill explicitly requires uploading the user's PDF to an external third-party API, which is a real data exfiltration/privacy risk because PDFs often contain sensitive business or personal information. In this context the transmission is core functionality rather than covert malware behavior, but it is still dangerous because the document leaves the local trust boundary and is processed by a remote service outside the user's control.

External Transmission

Medium
Category
Data Exfiltration
Content
1) Upload PDF to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/41`
2) Poll:
   `GET  https://api.xss-cross-service-solutions.com/solutions/solutions/api/<job_id>`
3) Return `output.files[0].path` as the download URL

## Script (CLI)
Confidence
95% confidence
Finding
Polling the external API and returning output.files[0].path continues the same external-service trust issue: the workflow depends on a remote system for document handling and then returns a remote download URL, which may expose users to unvetted storage locations or leaked access URLs. This is especially sensitive because the skill markets the output as 'safe,' which could cause users to upload confidential PDFs with reduced skepticism.

External Transmission

Medium
Category
Data Exfiltration
Content
## API endpoints
Base URL:
- `https://api.xss-cross-service-solutions.com/solutions/solutions`

Create make-safe job:
- `POST /api/41`
Confidence
91% confidence
Finding
The skill is explicitly designed to upload user-supplied PDFs to an external third-party API, which is a real data exfiltration boundary and creates confidentiality, privacy, and compliance risk for potentially sensitive documents. Although this transmission is central to the skill’s stated purpose and appears disclosed rather than covert, sending documents off-platform is still security-relevant because users may assume a 'make safe' operation is local or inherently trustworthy.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests


DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions"
CREATE_PATH = "/api/41"
Confidence
88% confidence
Finding
The hardcoded external endpoint shows that the skill transmits data to an internet-hosted service. In this skill's context, external transmission is core functionality, but it still materially increases risk because the uploaded document and resulting download URL depend on a third-party service and because the base URL can be overridden to alternate destinations.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script uploads the user's PDF to a remote API during normal operation, but it does not present an explicit runtime warning or consent step at the point of execution. This is risky because PDFs can contain sensitive business or personal information, and users may assume 'safe' processing is local when it is actually sent to a third party.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.32.0
Confidence
97% confidence
Finding
The dependency is specified as `requests>=2.32.0`, which allows future releases to be installed without review and prevents reproducible builds. In a security-sensitive skill that uploads user-provided PDFs to a remote API, this increases supply-chain risk and makes it harder to ensure the installed version is not affected by newly introduced vulnerabilities or breaking security changes.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding
Because `requests` is not pinned, it is impossible to verify from this manifest whether the installed version is affected by known advisories. This skill performs network operations against an external API and likely handles URLs, polling, and possibly authentication, so ambiguity around the exact `requests` version leaves open the possibility of exposure to known library flaws such as credential leakage or transport/security issues.

Static analysis

No suspicious patterns detected.