Back to skill

Security audit

Remove password from PDF

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it uploads protected PDFs, passwords, and API credentials to a remote service and allows that destination to be redirected too broadly.

Review this skill carefully before installing. Use it only for PDFs you are allowed to upload to the named third-party service, avoid confidential documents unless the provider's retention and security terms are acceptable, keep the API key in a protected environment variable, and do not use --base-url unless it is restricted to a trusted HTTPS endpoint.

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/remove-password-from-pdf.py:57
Finding
Unrestricted Base URL Override Can Redirect Sensitive Documents and Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/remove-password-from-pdf.py`, lines 57-64 and 193-198 **Vulnerability Type**: Unvalidated external request destination **Risk Level**: High ### Vulnerable Code ```python def create_job( base_url: str, api_key: str, pdf_path: str, password: str, timeout_s: int = 120, ) -> Dict[str, Any]: 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")} data = {"password": password} resp = requests.post(url, headers=headers, files=files, data=data, timeout=timeout_s) ``` The destination can be overridden through either a command-line argument or an environment variable: ```python ap.add_argument( "--base-url", default=os.getenv("SOLUTIONS_BASE_URL", DEFAULT_BASE_URL), help="Base URL override", ) ``` Polling requests subsequently send the same Bearer credential to the selected destination: ```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) ``` ### Technical Analysis The skill's declared functionality requires transmitting the protected PDF, its current password, and an API key to the documented Solutions API. Sending these values to the default provider endpoint is therefore expected and necessary for the declared cloud-based workflow. However, the implementation allows `base_url` to be replaced without validating: - The URL scheme - The destination hostname - Whether TLS is required - Whether the destination belongs to the declared provider - Whether credentials may be sent to the selected origin As a result, `SOLUTIONS_BASE_URL` or `--base-url` can redirect the upload to an arbitrary HTTP or HTTP ...[truncated 1863 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the base URL override if alternate service deployments are not an essential requirement. 2. If configurability is required, parse the destination with `urllib.parse.urlparse` and enforce: - Scheme must be `https` - Hostname must exactly match an explicit allowlist - Port must be an approved TLS port - User information and URL fragments must be absent - The expected API path must not be replaceable 3. Reject plaintext HTTP destinations, including local and loopback destinations. 4. Construct endpoints from a validated origin rather than concatenating untrusted strings. 5. Disable redirects for credential-bearing requests or validate every redirect target before following it: ```python requests.post(..., allow_redirects=False) ``` 6. Avoid forwarding the `Authorization` header across origins under all circumstances. 7. Document any approved alternate provider endpoints and require explicit administrative configuration rather than accepting unrestricted per-run overrides. 8. Add tests confirming that HTTP URLs, unknown hosts, embedded credentials, malformed URLs, and cross-origin redirects are rejected before opening or uploading the PDF. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/remove-password-from-pdf.py:190
Finding
PDF Password and API Key Can Be Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/remove-password-from-pdf.py`, lines 190-198; `README.md`, lines 26-29 **Vulnerability Type**: Sensitive information exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```python ap = argparse.ArgumentParser(description="Remove password from a PDF via Solutions API.") ap.add_argument("--pdf", required=True, help="Path to input PDF") ap.add_argument("--password", required=True, help="Current password (will not be echoed)") ap.add_argument("--api-key", default=os.getenv("SOLUTIONS_API_KEY", ""), help="Solutions API key (Bearer token)") ap.add_argument( "--base-url", default=os.getenv("SOLUTIONS_BASE_URL", DEFAULT_BASE_URL), help="Base URL override", ) ``` The documented invocation encourages passing the PDF password directly on the command line: ```bash python scripts/remove_password_from_pdf.py \ --pdf "/path/to/protected.pdf" \ --password "CurrentPasswordHere" \ --api-key "$SOLUTIONS_API_KEY" ``` ### Technical Analysis The implementation avoids explicitly printing the password, but accepting a secret through `argparse` does not prevent its exposure outside the Python process. Command-line arguments may be observable through: - Process inspection interfaces and tools - Process-monitoring or endpoint-security software - Audit and telemetry systems - CI/CD job logs - Shell history - Debugging output or wrapper scripts The PDF password must always be supplied through `--password`. The API key defaults to an environment variable, but the exposed `--api-key` option and documented example permit it to be supplied as a process argument as well. Expanding `$SOLUTIONS_API_KEY` in a shell places its resolved value in the process argument vector, even though the command text retained in shell history may contain only the variable reference. ### Attack Path 1. A user follows the documented example and starts the script with `--password` and o ...[truncated 1195 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--password` argument and collect the PDF password through a non-echoing prompt: ```python import getpass password = getpass.getpass("PDF password: ") ``` 2. For non-interactive use, support a protected secret file descriptor, standard input with explicit safeguards, or integration with an operating-system credential store. 3. Remove the `--api-key` argument and accept the token only through a protected environment variable or credential manager. 4. If secret files are supported, verify restrictive ownership and permissions before reading them. 5. Update the README and module usage examples so that they never encourage literal secrets in command-line arguments. 6. Warn users that environment-variable expansion in a command argument still exposes the expanded value in the child process's argument vector. 7. Ensure CI/CD integrations use masked secret injection and do not enable command tracing such as `set -x`. 8. Continue avoiding passwords and authorization headers in application logs, exception messages, and returned JSON. ]]>
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
93% confidence
Finding
The skill makes external network calls to a remote API while also handling sensitive inputs, yet this capability is not covered by declared permissions. In practice, undeclared network capability is dangerous because it enables covert transmission of documents, passwords, and API tokens in a context where operators may assume no such access exists.

Lp1

High
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill makes external network calls to a remote API while also handling sensitive inputs, yet this capability is not covered by declared permissions. In practice, undeclared network capability is dangerous because it enables covert transmission of documents, passwords, and API tokens in a context where operators may assume no such access exists.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README explicitly instructs users to send a password-protected PDF, the current password, and an API key to a third-party remote service, but it does not clearly warn that sensitive document contents and credentials leave the local environment. This creates a real privacy and data-handling risk because users may unknowingly transmit confidential files and secrets to an external processor.

External Transmission

Medium
Category
Data Exfiltration
Content
## How it works
1) Upload PDF + current password to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/33`
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
90% confidence
Finding
This line documents an outbound POST request to an external domain that receives both the protected PDF and its current password. In the context of a document-unlocking skill, this transmission is functionally required, but it is still security-relevant because it exports sensitive content and secrets to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
1) Upload PDF + current password to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/33`
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
82% confidence
Finding
This line documents polling a third-party API for job status, which confirms continued interaction with an external service and may expose metadata such as job identifiers and usage patterns. While less sensitive than the initial upload, it still expands the external data-sharing surface and reinforces that processing occurs off-box.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill’s description does not clearly warn the user that both the uploaded PDF and its current password will be transmitted to a third-party external API. Because this skill handles highly sensitive document contents and a decryption secret, lack of explicit user-facing disclosure can mislead users into exposing confidential material to an external service they may not expect.

External Transmission

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

Create remove-password job:
- `POST /api/33`
Confidence
91% confidence
Finding
This skill is explicitly designed to send a password-protected PDF and its password to an external service endpoint, which creates a real confidentiality risk if the document contains sensitive information or if the service is compromised, logs inputs, or retains data. The skill context makes this more dangerous than ordinary API use because it transmits both the protected content and the secret needed to decrypt it.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This script uploads both the protected PDF and its current password to a third-party API, but the user-facing description and CLI behavior do not prominently warn that sensitive document contents and credentials leave the local system. That creates a real risk of unintended disclosure of confidential files, especially because users may expect a local password-removal operation.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests


DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions"
CREATE_PATH = "/api/33"
Confidence
95% confidence
Finding
The code is hardwired to send sensitive files and passwords to an external domain, which is inherently risky in a skill that processes protected documents. The risk is amplified by the suspicious domain naming and by the fact that the skill's core function is deprotection of confidential material, making external transmission particularly sensitive in context.

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 future, unreviewed versions to be installed and makes builds non-reproducible. In a security-sensitive skill that uploads password-protected PDFs and handles credentials, this increases supply-chain risk because behavior and security posture may change over time without explicit review.

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
86% confidence
Finding
The manifest references `requests` without an exact pinned version, so it is not possible to verify whether the installed release avoids known advisories affecting some versions of the library. Given this skill uploads protected documents and their passwords to an external API, uncertainty around a networking library's security is more concerning because request handling, redirects, or credential exposure bugs could affect sensitive data in transit or logs.

Static analysis

No suspicious patterns detected.