Back to skill

Security audit

Protect PDF with password

Security checks for vulnerabilities and agentic risk

Overview

This skill does the advertised PDF password-protection task, but it handles sensitive PDFs, passwords, and API tokens with under-scoped endpoint and command-line secret risks that warrant Review before installation.

Install only if you are comfortable sending the PDF, the chosen password, and a Solutions API bearer token to an external service. Avoid confidential PDFs or reused passwords, prefer SOLUTIONS_API_KEY over command-line tokens, do not pass secrets directly in shell commands, and do not use SOLUTIONS_BASE_URL or --base-url unless you fully trust and validate the destination.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/password-protect-pdf.py:193
Finding
Arbitrary API base URL permits disclosure of the PDF, password, and Bearer token## Vulnerability Details **File Location**: `scripts/password-protect-pdf.py:30, 57-64, 82-86, 193-197` **Vulnerability Type**: Unrestricted sensitive-data transmission endpoint **Risk Level**: High ### Vulnerable Code ```python DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions" ``` ```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 = {"userPass": password} 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 Uploading the PDF and its password to the documented Solutions API is explicitly declared by the Skill and is necessary for its remote-service design. However, the implementation allows the destination to be replaced through either the `SOLUTIONS_BASE_URL` environment variable or the `--base-url` argument. The replacement URL is not restricted to the documented service, validated against an approved hostname, or required to use HTTPS. The same Bearer token intended for the legitimate service is attached to requests sent to the replacement destination. The initial POST also contains the complete PDF and the password supplied for protecting it. This ...[truncated 1387 chars]
Remediation
## Remediation Suggestions - Remove `--base-url` and `SOLUTIONS_BASE_URL` support if alternate service instances are not a strict functional requirement. - Hardcode the documented HTTPS origin and construct request paths from that trusted origin. - If endpoint configurability is required, parse the URL and enforce: - The `https` scheme. - An explicit allowlist of approved hostnames. - An expected port. - No embedded credentials. - No redirects to unapproved origins. - Configure requests not to forward authorization credentials across redirects. Validate the final response origin when redirects are permitted. - Use separate, non-production credentials for approved development endpoints. - Require explicit user confirmation before uploading a document to a non-default approved environment. - Document that the PDF and its password are transmitted to a third-party processor and clarify the service's retention and privacy expectations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/password-protect-pdf.py:189
Finding
PDF password and API key can be exposed through command-line arguments## Vulnerability Details **File Location**: `scripts/password-protect-pdf.py:189-192`; `README.md:26-29` **Vulnerability Type**: Sensitive information exposed through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```python ap = argparse.ArgumentParser(description="Password-protect a PDF via Solutions API.") ap.add_argument("--pdf", required=True, help="Path to input PDF") ap.add_argument("--password", required=True, help="Password for PDF (will not be echoed)") ap.add_argument("--api-key", default=os.getenv("SOLUTIONS_API_KEY", ""), help="Solutions API key (Bearer token)") ``` The documented invocation encourages passing both values through the command line: ```bash python scripts/password_protect_pdf.py \ --pdf "/path/to/file.pdf" \ --password "YourPasswordHere" \ --api-key "$SOLUTIONS_API_KEY" ``` ### Technical Analysis Although the script does not intentionally print the password or API key in its JSON output, command-line arguments are outside that protection. Depending on the operating system and execution environment, arguments can be exposed through process-listing tools, process telemetry, audit systems, job-runner logs, crash diagnostics, shell history, or orchestration metadata. Expanding an environment variable in a command such as `--api-key "$SOLUTIONS_API_KEY"` still places the expanded secret in the process argument vector. The claim that the password “will not be echoed” therefore does not fully describe the actual exposure. ### Attack Path 1. A user follows the documented example and supplies the password and API key as command-line arguments. 2. The shell may retain the command in its history, including a literal password. 3. While the process is running, another authorized local user or monitoring component reads its argument vector. 4. Alternatively, an automation platform records the complete command in execution logs or telemetry. 5. The obse ...[truncated 539 chars]
Remediation
## Remediation Suggestions - Prompt for the PDF password through `getpass.getpass()` rather than requiring `--password`. - Obtain the API key exclusively from a protected environment variable, secret manager, or restricted credential file. - Remove or deprecate `--api-key` and `--password`. - If non-interactive password input is required, support a file descriptor, standard input, or a restricted file rather than an argument. - Update the README so examples do not place secrets in the command line. - Warn users that environment variables may also be visible to privileged processes and should be injected through the platform's secret-management facility. - Avoid logging parsed arguments and ensure wrappers, CI jobs, and orchestration systems redact secret fields.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Open-ended dependency constraint prevents reproducible dependency resolution## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```text requests>=2.32.0 ``` ### Technical Analysis The lower-bound-only constraint allows any future `requests` release to be installed without review. This makes installations non-reproducible and expands the supply-chain trust boundary beyond the version examined during the audit. The package name is the legitimate `requests` package, and no typosquatting, custom package index, or known malicious package was identified. The risk is therefore the uncontrolled acceptance of future versions rather than evidence that the current dependency is malicious. This dependency processes requests containing a Bearer token, a sensitive PDF, and its intended password, making controlled dependency updates especially important. ### Attack Path 1. A future release satisfying `requests>=2.32.0` becomes available. 2. A new installation or build resolves that release automatically. 3. The Skill executes dependency code that was not part of the reviewed project state. 4. If that release is compromised or introduces a security regression, sensitive network operations may be affected. ### Impact Assessment The potential impact depends on the behavior of a future compromised or vulnerable dependency release. Because `requests` operates in the Skill's process, such code could theoretically access process memory, environment variables, files readable by the process, and network request contents. No current compromise was found, and this finding does not establish an immediately exploitable vulnerability in the reviewed `requests` version.
Remediation
## Remediation Suggestions - Pin `requests` and its transitive dependencies to reviewed versions. - Generate and commit a lock file appropriate for the project's package-management workflow. - Use hashes for dependency artifacts, such as through `pip-compile --generate-hashes`. - Install with hash verification in controlled builds. - Use an automated dependency-update process that runs security checks and tests before accepting new versions. - Periodically review pins so reproducibility does not result in indefinitely retaining vulnerable releases.
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
95% confidence
Finding
This skill initiates network communication to a remote API while processing sensitive inputs, yet that capability is reportedly not covered by declared permissions. In a skill system, missing permission declarations undermine sandboxing and informed trust because the component can exfiltrate files or secrets beyond what reviewers and users expect.

Lp1

High
Category
MCP Least Privilege
Confidence
95% confidence
Finding
This skill initiates network communication to a remote API while processing sensitive inputs, yet that capability is reportedly not covered by declared permissions. In a skill system, missing permission declarations undermine sandboxing and informed trust because the component can exfiltrate files or secrets beyond what reviewers and users expect.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README explicitly instructs users to send a PDF, the chosen password, and an API bearer token to a third-party remote service, but it does not clearly warn that document contents and secrets are being disclosed outside the local environment. This is dangerous because users may assume the skill operates locally and may upload sensitive PDFs or reuse important passwords, exposing confidential data to an external provider.

External Transmission

Medium
Category
Data Exfiltration
Content
## How it works
1) Upload PDF + password to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/32`
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
87% confidence
Finding
This line documents a POST request to an external API endpoint that receives the PDF and password, which constitutes transmission of sensitive content and secrets to a third party. In the context of a password-protection skill, external transmission is not inherently malicious, but it becomes security-relevant because the README does not frame the privacy and trust implications for users.

External Transmission

Medium
Category
Data Exfiltration
Content
1) Upload PDF + password to:
   `POST https://api.xss-cross-service-solutions.com/solutions/solutions/api/32`
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
50% 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
96% confidence
Finding
The skill handles highly sensitive inputs—a PDF and its password—but does not clearly warn users in the main behavior/inputs flow that both are transmitted to an external third-party API. This creates a meaningful privacy and confidentiality risk because users may assume processing is local or agent-native and submit sensitive documents or secrets without informed consent.

External Transmission

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

Create password-protect job:
- `POST /api/32`
Confidence
86% confidence
Finding
The skill is explicitly designed to send user-supplied files and passwords to an external service endpoint, which is a real data exfiltration surface even if it is part of intended functionality. Because the transmitted data includes document contents and the protection password itself, compromise, logging, retention, or misuse by the third party could expose sensitive material.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests


DEFAULT_BASE_URL = "https://api.xss-cross-service-solutions.com/solutions/solutions"
CREATE_PATH = "/api/32"
Confidence
94% confidence
Finding
The code hardcodes an external service endpoint and sends sensitive document data to it. External transmission is materially more dangerous in this skill context because the feature involves protecting confidential PDFs, yet it depends on exporting both the file and associated secret to an outside system, expanding exposure to compromise, logging, retention, and supply-chain risk.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script uploads both the PDF contents and the user-chosen password to a third-party service, but at execution time it provides no explicit warning or confirmation that highly sensitive material is leaving the local environment. This is especially risky because passwords and document contents may contain confidential data, and users may assume the operation is local based on the skill name alone.

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 versions to be installed without review and makes builds non-reproducible. In a skill that uploads PDFs to a remote API and may handle sensitive documents, uncontrolled dependency resolution increases supply-chain risk and can unintentionally pull in a vulnerable or breaking release.

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
91% confidence
Finding
Because `requests` is not pinned, it is not possible to verify from this manifest whether the installed version includes fixes for known advisories. Given that this skill communicates with an external service and may transmit sensitive PDF data or credentials, uncertainty about the exact HTTP client version raises supply-chain and data-exposure concerns.

Static analysis

No suspicious patterns detected.