Back to skill

Security audit

Cloudflare R2 CLI

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Cloudflare R2 storage CLI, but it handles powerful credentials and destructive storage actions with under-disclosed safety gaps.

Review before installing. Use a narrowly scoped R2 key, avoid broad delete/write permissions unless needed, install dependencies in an isolated environment, and treat download paths and delete commands carefully because they can overwrite local files or remove remote objects immediately.

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
r2.py:158
Finding
Signed Authorization Headers May Be Forwarded to an Unvalidated Redirect Destination## Vulnerability Details **File Location**: `r2.py`, lines 158–174 **Vulnerability Type**: Authorization header exposure through automatic cross-origin redirects **Risk Level**: High ```python _validate_url(url) headers = _aws_headers(method, canonical_uri, query, body) req = urllib.request.Request( url, data=body if body else None, headers=headers, method=method, ) # Create restricted opener (HTTPS only) opener = urllib.request.build_opener( urllib.request.HTTPSHandler() ) try: with opener.open(req, timeout=30) as resp: # nosec B310 return resp.status, resp.read() ``` ### Technical Analysis The code validates only the initial URL before creating the request. The opener constructed by `urllib.request.build_opener()` includes standard redirect handling in addition to the explicitly supplied HTTPS handler. Redirect destinations are therefore not passed through `_validate_url()`. Request headers supplied through the `Request` constructor can be copied to a redirected request. This may include the AWS Signature Version 4 `Authorization` header, the R2 access-key identifier contained in its credential scope, `x-amz-date`, and `x-amz-content-sha256`. HTTPS enforcement alone does not prevent disclosure because an attacker-controlled redirect destination can also use HTTPS. Moreover, the current hostname check at line 139 uses: ```python if not parsed.netloc.endswith("cloudflarestorage.com"): raise ValueError("Unexpected host") ``` A suffix comparison without a hostname boundary is weaker than comparison against the exact expected R2 hostname. Validation should use `parsed.hostname` and an exact allowlist. ### Attack Path 1. A user invokes an operation such as `download`, `list`, or `delete`. 2. `_aws_headers()` generates a signed request containing the access-key identifier and AWS Signature Version 4 authentication material. 3. The Cloudflare endpoint, ...[truncated 1289 chars]
Remediation
## Remediation Suggestions - Disable automatic redirects by installing a custom `urllib.request.HTTPRedirectHandler` that rejects every redirect. - If redirects are operationally required, validate every redirect target before following it. - Require `parsed.scheme == "https"` and compare `parsed.hostname` against the exact expected hostname: ```python expected_host = f"{ACCOUNT_ID}.r2.cloudflarestorage.com" if parsed.scheme != "https" or parsed.hostname != expected_host: raise ValueError("Unexpected destination") ``` - Reject URLs containing user information, unexpected ports, fragments, or other authority ambiguity. - Never forward an existing `Authorization` header across origins. - Regenerate the AWS Signature Version 4 header only after an approved redirect destination and canonical request have been validated. - Add automated tests covering cross-origin redirects, same-origin redirects, HTTPS-to-HTTP redirects, suffix-confusion hostnames, and redirects containing user information.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:27
Finding
Third-Party Dependency Is Installed Without Version Locking or Integrity Verification## Vulnerability Details **File Location**: `SKILL.md`, lines 27–29 and 71–75 **Vulnerability Type**: Unpinned and unhashed third-party dependency installation **Risk Level**: Medium ```yaml dependencies: - "defusedxml>=0.7.1" ``` ```markdown If `defusedxml` is not already available: ```bash pip install defusedxml ``` ``` ### Technical Analysis The declared version constraint accepts any current or future release greater than or equal to version 0.7.1. The documented installation command is even less restrictive and asks `pip` to resolve the latest available version from its configured package index. No lock file, exact version, package hash, or trusted index configuration is provided. Consequently, installations are not reproducible and package content is not cryptographically checked against a project-controlled expectation. Python package installation may execute package-controlled build logic. A compromised future release, compromised package index, or malicious package supplied through an untrusted index configuration could therefore execute code with the privileges of the user performing installation. ### Attack Path 1. A user follows the documented installation command or installs dependencies from the permissive metadata. 2. `pip` queries the package indexes configured in the user's environment. 3. The resolver selects any available release satisfying the mutable constraint. 4. A compromised release or package served through a malicious or incorrectly prioritized index is downloaded. 5. Package build or installation logic executes locally, or malicious runtime code executes when `r2.py` imports `defusedxml`. 6. The malicious dependency gains the privileges of the installing or invoking user and can access the Cloudflare R2 credentials inherited through environment variables. ### Impact Assessment Successful supply-chain exploitation could execute arbitrary Python code under the account ins ...[truncated 585 chars]
Remediation
## Remediation Suggestions - Pin `defusedxml` to an exact, reviewed version rather than using a lower-bound-only constraint. - Maintain a dependency lock file and review dependency updates deliberately. - Record and enforce package hashes using a requirements file: ```text defusedxml==REVIEWED_VERSION \ --hash=sha256:EXPECTED_PACKAGE_HASH ``` - Install with hash enforcement: ```bash python -m pip install --require-hashes -r requirements.txt ``` - Explicitly document and enforce the trusted package index, such as the official PyPI simple index, while preventing unintended fallback to untrusted indexes. - Perform dependency vulnerability and provenance checks in continuous integration. - Install dependencies in an isolated virtual environment using an unprivileged account.
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The documentation states that paths are sanitized to prevent injection/path traversal, suggesting protective handling of filesystem paths. In practice, `download()` opens whatever `file_path` the user supplies and writes to it directly, with no normalization, restriction, or traversal checks.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code writes downloaded object data directly to a user-specified local path, which can modify or overwrite local files. Although the script prints success/failure messages, there is no warning, confirmation, or comment/docstring near the operation disclosing that the command performs a local file write.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The delete command issues a DELETE request against the remote object and only reports the outcome afterward. There is no prior confirmation prompt, warning comment, or user-facing disclosure near this destructive action that it permanently removes remote data.

Intent-Code Divergence

Low
Confidence
99% confidence
Finding
The module docstring explicitly says the tool uses only Python's standard library and has no external dependencies. However, the code imports `defusedxml`, which is a third-party package and directly contradicts that claim.

Static analysis

No suspicious patterns detected.