Back to skill

Security audit

Change permissions of PDF

Security checks for vulnerabilities and agentic risk

Overview

This PDF tool mostly does what it says, but it can be configured to send the PDF and API key to an arbitrary server, so it needs careful review before installation.

Review before installing. Only use this skill if you are comfortable sending the selected PDF and a Solutions API bearer token to an external PDF-processing service. Do not set --base-url or SOLUTIONS_BASE_URL unless it is a trusted HTTPS endpoint you control, and prefer a scoped API key. Avoid highly sensitive PDFs until the provider's privacy and retention practices are acceptable to you.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/change-pdf-permissions.py:207
Finding
Arbitrary API Endpoint Can Receive Sensitive PDFs and Bearer Tokens<![CDATA[ ## Vulnerability Details **File Location**: `scripts/change-pdf-permissions.py:85-92`, `scripts/change-pdf-permissions.py:108-112`, and `scripts/change-pdf-permissions.py:207-210` **Vulnerability Type**: Unrestricted sensitive-data destination **Risk Level**: High ### Vulnerable Code ```python def create_job( base_url: str, api_key: str, pdf_path: str, permissions: Dict[str, bool], timeout_s: int = 180, ) -> Dict[str, Any]: url = base_url.rstrip("/") + CREATE_PATH headers = make_headers(api_key) data = {k: bool_to_api(bool(v)) for k, v in permissions.items()} 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, data=data, timeout=timeout_s) ``` ```python def get_job( base_url: str, api_key: str, job_id: Any, timeout_s: int = 30, ) -> Dict[str, Any]: 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 Skill's declared functionality requires uploading a user-selected PDF and an API bearer token to the documented Solutions API. That transfer is necessary for the remote-processing design and is disclosed in `SKILL.md`. However, the implementation permits the destination to be replaced through either the `--base-url` command-line argument or the `SOLUTIONS_BASE_URL` environment variable. It does not validate the URL scheme, hostname, port, or expected path before attaching the bearer token and PDF to the request. Consequently, an attacker who can influence the invocation arguments or process environment can redirect the request to an arbitrary server. An `http://` destination would also send the data without ...[truncated 1497 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` and `SOLUTIONS_BASE_URL` support if alternate service deployments are not a documented requirement. 2. Otherwise, parse the configured URL with `urllib.parse.urlparse` and enforce: - The `https` scheme. - The exact approved hostname. - The expected port. - The documented base path. - No embedded username or password. 3. Reject malformed URLs, plain HTTP, IP-literal substitutions, lookalike domains, unexpected ports, and URLs containing fragments. 4. Disable automatic redirects for authenticated uploads, or validate every redirect destination before resending sensitive content. 5. Attach the `Authorization` header only after destination validation. 6. Consider requiring an explicit, interactive confirmation before uploading a document to any non-default deployment. 7. Document clearly that PDFs are transferred to a third-party processor, including applicable retention and privacy implications. 8. Add tests confirming that attacker-controlled hosts and plaintext URLs are rejected before the file is opened or any credential is transmitted. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned Dependency Permits Unreviewed Future Releases<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Non-reproducible dependency resolution **Risk Level**: Low ### Vulnerable Code ```text requests>=2.32.0 ``` ### Technical Analysis The dependency specification sets only a minimum version and has no upper bound, exact version, lock file, or integrity hash. Therefore, separate installations can resolve to different future versions of `requests` and its transitive dependencies. No malicious package or currently vulnerable version was identified in the audited project. The risk is that future, unreviewed releases or a compromised package distribution could enter the execution environment automatically. This is particularly relevant because `requests` handles the Skill's confidential PDF uploads and bearer-token-bearing HTTP requests. ### Attack Path 1. A future release of `requests` or one of its transitive dependencies becomes compromised or introduces security-relevant behavior. 2. A user installs the project after that release is available. 3. The package resolver selects the new release because it satisfies the open-ended minimum constraint. 4. The affected dependency executes when the script imports or uses `requests`. 5. Malicious or vulnerable dependency behavior can intercept documents, credentials, network traffic, or code execution within the privileges of the Python process. ### Impact Assessment A compromised dependency executes with the same operating-system privileges as the Skill process. It could access the API token held in process memory, inspect uploaded PDF data, alter requests and responses, or access other resources available to that process. The finding represents supply-chain exposure rather than evidence of an existing malicious dependency. Its likelihood is lower than the arbitrary-endpoint issue, but the potential scope is process-level compromise. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `requests` and all transitive dependencies to reviewed, exact versions. 2. Generate and commit a lock file using an appropriate dependency-management tool. 3. Record cryptographic hashes and install with hash verification, such as pip's `--require-hashes` option. 4. Review and test dependency upgrades before updating the lock file. 5. Use automated vulnerability and supply-chain monitoring for direct and transitive dependencies. 6. Perform installations only from trusted package indexes over authenticated TLS connections. ]]>
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 (11)

Lp1

High
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The code makes network requests to a remote service using requests.post and requests.get, yet this capability is not covered by declared permissions. In a hosted agent setting, undeclared network access can bypass user expectations and governance controls, especially since the tool uploads user-supplied files and returns remote URLs.

Lp1

High
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The code makes network requests to a remote service using requests.post and requests.get, yet this capability is not covered by declared permissions. In a hosted agent setting, undeclared network access can bypass user expectations and governance controls, especially since the tool uploads user-supplied files and returns remote URLs.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README instructs users to upload a PDF and provide an API key to a third-party service, but it does not clearly warn that document contents and credentials are being transmitted off-platform to an external provider. This can lead users to unknowingly expose sensitive files or use production credentials without understanding the privacy, retention, and trust implications.

External Transmission

Medium
Category
Data Exfiltration
Content
## How it works
1) Upload PDF + flags to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/75`
2) Poll:
   `GET  https://api.xss-cross-service-solutions.com/solutions/solutions/api/<job_id>`
3) Return `output.files[0].path` as download URL
Confidence
93% confidence
Finding
This step explicitly directs the user to upload the PDF to an external domain, which means the full document leaves the local environment and is processed by a third party. In the context of a file-processing skill, that is a real data-exposure risk if users assume the operation is local or are handling confidential documents.

External Transmission

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

## Script (CLI)
Confidence
84% confidence
Finding
The polling endpoint confirms that processing state and identifiers are handled through the same external service, reinforcing that the workflow depends on third-party transmission and storage rather than local-only processing. While expected for this type of integration, it is still security-relevant because users may disclose job metadata and retrieve outputs from an external system.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly uploads user-provided PDFs and permission settings to an external third-party API, but the skill text does not provide a clear user-facing warning at the point where data handling is described. This creates a real privacy and data-governance risk because users may provide sensitive documents without informed consent about off-platform transmission.

External Transmission

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

Create permission-change job:
- `POST /api/75`
Confidence
84% confidence
Finding
The skill is designed around sending documents to an external API endpoint, which means potentially sensitive PDF contents leave the local/trusted environment. In this document-security context, that is especially important because users may assume the operation is local or privacy-preserving when it is not.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests


DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions"
CREATE_PATH = "/api/75"
Confidence
86% confidence
Finding
The hardcoded external endpoint confirms that this skill is designed to communicate with a third-party service, which expands the trust boundary beyond the local environment. In this skill context that is expected functionality, but it still creates confidentiality and supply-chain risk because uploaded PDFs and bearer tokens depend on the security of that external service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script uploads the entire PDF file to a remote API, but it does not present an explicit warning or consent mechanism about external data transmission at the point of use. This is dangerous because PDFs often contain sensitive business or personal data, and users may believe the operation is local when it is actually sending content off-system.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.32.0
Confidence
95% confidence
Finding
The dependency is specified as `requests>=2.32.0`, which allows any future version and does not guarantee a reproducible install. This can lead to builds picking up unexpectedly vulnerable or incompatible releases over time, which is a real supply-chain hardening weakness even though it is not an immediate exploit by itself.

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
89% confidence
Finding
Because `requests` is not pinned, there is no way to verify from this manifest whether the installed version avoids known advisories affecting some `requests` releases. In a skill that uploads documents to a remote API and likely handles URLs, network requests, and possibly authentication, uncertainty around the exact HTTP client version increases risk of exposure to known client-side flaws.

Static analysis

No suspicious patterns detected.