Back to skill

Security audit

Nutrition Provider R2

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed R2 upload helper for provider nutrition records, with expected credential and cloud-storage use but no hidden or destructive behavior found.

Install only if you intend to upload the provider records to a Cloudflare R2 bucket you control. Use R2 credentials scoped to the target bucket and prefix, avoid exposing unrelated secrets in the environment, review payloads before upload, and prefer pinned or locked Python dependencies for repeatable runs.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (1)

T08 · Insecure Dependencies

Warning
Location
scripts/upload_page_to_r2.py:3
Finding

Unbounded Runtime Dependency Resolution

Content
View full analysis
=3.10" # dependencies = [ # "boto3>=1.34.0", # "botocore>=1.34.0", # ] # /// ``` ### Technical Analysis The helper is intended to be executed through `uv run`, which resolves the inline dependencies at runtime. Both `boto3` and `botocore` use open-ended minimum-version constraints rather than exact, audited versions. Consequently, any future package release satisfying these constraints may be downloaded, imported, and executed without being represented in the reviewed project source. This creates a supply-chain exposure: compromise of a future compatible package release or its distribution channel could alter the effective code executed by the Skill. No evidence was found that the currently named packages are malicious; the risk arises from unconstrained future dependency resolution. The dependency code executes in the same process and security context as the upload helper. It can therefore access the R2 credentials loaded from the environment, provider records supplied through files or standard input, network connectivity, and any files available to the invoking operating-system account. ### Attack Path 1. An attacker compromises a future release of `boto3`, `botocore`, or the relevant package-distribution path. 2. The malicious release retains a version number satisfying `>=1.34.0`. 3. A user invokes the documented `uv run scripts/upload_page_to_r2.py ...` workflow in an environment without a restrictive lockfile or previously fixed resolution. 4. `uv` resolves and installs the compromised compatible version. 5. Python imports the dependency before the helper performs its upload. 6. Malicious initialization code reads `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_ACCOUNT_ID`, or the provider payload and transmits ...[truncated 909 chars]
Remediation
View remediation
", # "botocore==", # ] # /// ``` The placeholders should be replaced with mutually compatible versions that have been reviewed and recorded in the project's lockfile. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code accurately covers only the upload portion of the declared behavior: it uploads raw payloads or per-record extracted JSON objects to Cloudflare R2, supports stable object key generation, and can upload records from a page in parallel. However, the declared description's primary framing is a crawler that page-fetches provider data using scrapling-official and respects page timing constraints. None of that exists here. This script does not crawl, does not fetch remote provider pages or APIs, does not depend on scrapling-official, and does not implement any inter-page scheduling or 60-second throttling/window logic. Therefore the description materially overstates and mischaracterizes the actual code behavior.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill requests access to environment variables and local files by instructing the agent to read credential-bearing variables and source-notes, but it does not declare any explicit tool scope or permission boundary. In an agent environment, missing scope declarations can cause over-broad access and make secret handling less auditable, especially because the workflow explicitly relies on R2 credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill repeatedly instructs the agent to upload raw fetched records and possibly debug artifacts to Cloudflare R2 without requiring explicit user acknowledgement that data is being transmitted to third-party storage. Even if the target dataset appears public, raw payloads and failure artifacts can include unexpected sensitive content, metadata, or tokens, making silent exfiltration off-system risky.

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/upload_page_to_r2.py (reported line 239)May include surrounding context.

python
def upload_object(client, bucket: str, key: str, payload: bytes, content_type: str, skip_existing: bool) -> str:
    if skip_existing and object_exists(client, bucket, key):
        return f"skipped s3://{bucket}/{key} ({content_type})"
    client.put_object(Bucket=bucket, Key=key, Body=payload, ContentType=content_type)
    return f"uploaded s3://{bucket}/{key} ({content_type})"

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.txt (reported line 13)May include surrounding context.

text
so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN

Static analysis

No suspicious patterns detected.