Back to skill

Security audit

Cloudflare R2 S3 存储工具

Security checks for vulnerabilities and agentic risk

Overview

This is a real Cloudflare R2 upload tool, but it defaults toward public sharing and includes deletion of bucket objects without confirmation.

Install only if you are comfortable giving the skill write/delete access to the configured R2 bucket. Use a dedicated bucket and restricted R2 token, avoid uploading secrets or private documents, pass --private or public=False when needed, and manually confirm object names before using delete because the tool has no built-in confirmation.

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

Warning
Location
scripts/r2_uploader.py:27
Finding

Uploads Default to Public and the Private-by-Default Environment Setting Is Ignored

Content
View full analysis

Vulnerability Details

File Location: scripts/r2_uploader.py:27-58, scripts/r2_uploader.py:145-149, and scripts/r2_uploader.py:248-252
Vulnerability Type: Insecure access-control default
Risk Level: Medium

The constructor assigns True to default_public by default:

python
default_public: bool = True,

The environment variable is consulted only when default_public is None. Because ordinary construction uses the non-null default value True, CLOUDFLARE_R2_DEFAULT_PUBLIC=false is ignored:

python
self.public_domain = public_domain or os.getenv("CLOUDFLARE_R2_PUBLIC_DOMAIN")
self.default_public = default_public if default_public is not None else \
    os.getenv("CLOUDFLARE_R2_DEFAULT_PUBLIC", "true").lower() == "true"

Public uploads request a public-read ACL:

python
extra_args = {}
if public:
    extra_args['ACL'] = 'public-read'

The command-line interface also makes uploads public unless the user explicitly supplies --private:

python
result = uploader.upload_file(
    args.file_path,
    args.object_name,
    public=not args.private
)

The example configuration reinforces this unsafe default at references/config_example.env:19:

env
CLOUDFLARE_R2_DEFAULT_PUBLIC=true

Technical Analysis

Access to uploaded data should fail closed. This implementation instead treats public access as the normal state and requires callers to opt out.

More importantly, the constructor's default argument prevents the documented environment variable from controlling behavior during normal initialization. Calling R2Uploader() sets default_public to True, so the conditional expression never evaluates CLOUDFLARE_R2_DEFAULT_PUBLIC. A user can therefore configure the variable as false and still receive public behavior.

In S3-compatible services that honor object ACLs, the code requests public-read. For an R2 bucket whose public devel ...[truncated 1649 chars]

Remediation
View remediation

Remediation Suggestions

  1. Change the default to private:

    python
    default_public: Optional[bool] = None
    
  2. Parse the environment setting only when no explicit argument is supplied, and use a secure fallback:

    python
    if default_public is None:
        self.default_public = (
            os.getenv("CLOUDFLARE_R2_DEFAULT_PUBLIC", "false").strip().lower()
            == "true"
        )
    else:
        self.default_public = default_public
    
  3. Replace the CLI's opt-out --private flag with an explicit opt-in --public flag:

    python
    upload_parser.add_argument(
        "--public",
        action="store_true",
        help="Explicitly request public access"
    )
    
  4. Pass public=args.public during upload so omitted flags remain private.

  5. Do not rely on object ACLs to provide privacy for objects stored in a publicly exposed R2 bucket. Use a separate private bucket for sensitive content, disable the bucket's public development/custom domain, and use short-lived presigned URLs when sharing is required.

  6. Return a public URL only when public access was explicitly requested and successfully verified. For private objects, return an object identifier or presigned URL instead.

  7. Update references/config_example.env so CLOUDFLARE_R2_DEFAULT_PUBLIC=false.

  8. Add tests confirming that R2Uploader() honors an environment value of false and that CLI uploads are private unless public access is explicitly requested.

T08 · Insecure Dependencies

Note
Location
SKILL.md:74
Finding

Third-Party Dependencies Are Installed Without Version or Integrity Constraints

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:74-77
Vulnerability Type: Unpinned and incomplete dependency specification
Risk Level: Low

The installation documentation instructs users to retrieve the current available boto3 release without a version constraint, lockfile, or integrity hash:

markdown
Need to install boto3:
```bash
pip install boto3
text

The implementation additionally imports `python-dotenv`, but that dependency is not declared by the documented installation command:

```python
import boto3
from botocore.config import Config
from dotenv import load_dotenv

Technical Analysis

Installing an unconstrained package from a mutable package index makes the effective dependency set vary over time. boto3 also resolves transitive dependencies such as botocore, jmespath, and s3transfer, meaning future installations can execute code that was not part of the audited project state.

The absence of hashes prevents installers from verifying that downloaded artifacts match artifacts approved by the project. The undeclared python-dotenv requirement can also encourage users to install packages manually, potentially selecting an incorrect package name or an unreviewed version.

No evidence was found that this project intentionally references a malicious package or unsafe custom package repository. The issue is supply-chain hardening and reproducibility rather than a confirmed malicious dependency.

Attack Path

  1. A user follows the documented pip install boto3 command.
  2. The package manager resolves whatever versions are available and compatible at that time.
  3. A compromised future release, compromised transitive dependency, or tampered distribution artifact could be selected because no reviewed version or hash is enforced.
  4. Dependency code executes in the user's Python environment during installation or when the uploader imports and invokes it.
  5. That code r ...[truncated 670 chars]
Remediation
View remediation

Remediation Suggestions

  1. Add a dependency manifest that explicitly includes both boto3 and python-dotenv.

  2. Pin reviewed direct and transitive dependency versions using a lockfile generated by a tool such as pip-tools, Poetry, or uv.

  3. Record cryptographic hashes and require their verification during installation:

    bash
    pip install --require-hashes -r requirements.txt
    
  4. Generate pinned dependencies from a minimal source file rather than manually maintaining transitive versions.

  5. Use automated dependency scanning and update tooling to review new versions before changing the lockfile.

  6. Update SKILL.md to direct users to the locked installation procedure instead of an unconstrained pip install boto3 command.

  7. Install dependencies in an isolated virtual environment with only the filesystem and network permissions required by the uploader.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared purpose emphasizes uploading files and obtaining public URLs, but the skill also supports listing and deleting bucket contents. This behavior mismatch is dangerous because users or orchestrators may grant trust based on the benign-seeming description while the skill has broader, potentially destructive cloud-storage capabilities.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill documentation indicates it relies on environment-provided credentials and can access cloud storage, but it does not declare any explicit tool scope or permissions boundary. In an agent setting, missing scope declarations reduces visibility and control over sensitive capabilities, increasing the risk of unintended credential use or unauthorized storage operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill encourages generating public URLs and enabling public access without warning that uploaded files may become accessible to anyone on the internet. This creates a clear risk of unintended data exposure, especially if users upload sensitive local files or assume access remains private.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation advertises file deletion but does not warn that deletion may be destructive or irreversible depending on bucket versioning and lifecycle settings. In agent-assisted use, omitted warnings can lead to accidental data loss when operators assume routine file-management behavior is safe.

Content

No source excerpt is available for this finding.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
76% confidence
Finding

The upload API can transfer local files to cloud storage and return a public URL, which is a classic exfiltration path if misused by an agent or prompt-driven workflow. Although this appears to be the intended feature rather than overtly malicious behavior, the combination of local file access, cloud upload, and public sharing materially increases the risk of sensitive-data leakage.

Content

Scanner excerpt · SKILL.md (reported line 42)May include surrounding context.

from scripts.r2_uploader import R2Uploader

uploader = R2Uploader() result = uploader.upload_file(local_path, object_name=None, public=True) print(result['public_url']) # 获取公开访问地址

text

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This example config uses Chinese-language comments and instructions throughout, which imposes a specific language on users without indicating any choice or opt-in. The policy allows locale constraints only when they are documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file’s natural-language descriptions, help text, and user-facing messages are entirely in Chinese, which imposes a specific language expectation without any opt-in or stated regional justification. Under the policy, locale or language constraints should be optional or explicitly documented as intentional and necessary.

Content

No source excerpt is available for this finding.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
55% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/r2_uploader.py (reported line 159)May include surrounding context.

python
extra_args['ContentType'] = content_type
        
        # 执行上传
        self.s3_client.upload_file(
            local_path,
            self.bucket_name,
            object_name,

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
55% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/r2_uploader.py (reported line 249)May include surrounding context.

python
extra_args['ContentType'] = content_type
        
        # 执行上传
        self.s3_client.upload_file(
            local_path,
            self.bucket_name,
            object_name,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The declared skill purpose says it configures R2 credentials and uploads files to obtain public links, but the implementation also exposes bucket listing and deletion capabilities. This expands the operational scope beyond what a user may reasonably expect, increasing the risk of unintended data disclosure through listing and destructive actions through deletion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The delete command removes an object immediately with no interactive confirmation, dry-run, safeguard, or warning. In an agent or CLI context, this makes accidental or prompt-induced destructive actions much more likely, especially because object names may be user-provided or inferred by an LLM.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.