Back to skill

Security audit

Photo to 3D

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says: it converts user-supplied images into 3D models using Gemini and Tripo3D, with no evidence of hidden persistence, deception, or unrelated data access.

Install only if you are comfortable sending selected images to Gemini and Tripo3D using your own API keys. Avoid sensitive, private, or regulated images unless those services' policies fit your needs. The publisher should narrow triggers, add explicit upload/third-party disclosure, and validate the returned model download URL before fetching it.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/photo_to_3d.py:181
Finding

Unvalidated Server-Provided Model URL Enables Arbitrary Network Requests

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Tainted flow: 'url' from os.environ.get (line 58, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 73)May include surrounding context.

python
},
    }

    resp = requests.post(url, json=payload, timeout=120)
    if resp.status_code != 200:
        print(f"❌ Gemini API 错误: {resp.status_code}")
        print(resp.text[:500])

Tainted flow: 'headers' from os.environ.get (line 115, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 119)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},

Tainted flow: 'headers' from os.environ.get (line 115, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 140)May include surrounding context.

python
print(f"  📤 图片已上传, token: {image_token[:20]}...")

    # 创建 image-to-3d 任务
    task_resp = requests.post(
        "https://api.tripo3d.ai/v2/openapi/task",
        headers={**headers, "Content-Type": "application/json"},
        json={"type": "image_to_model", "file": {"type": "png", "file_token": image_token}},

Tainted flow: 'headers' from os.environ.get (line 115, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 165)May include surrounding context.

python
start = time.time()
    while time.time() - start < max_wait:
        time.sleep(5)
        status_resp = requests.get(
            f"https://api.tripo3d.ai/v2/openapi/task/{task_id}",
            headers=headers,
            timeout=30,

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises behavior that requires environment access, file writes, and outbound network calls, but it does not declare any explicit tool scope or permissions. This creates a transparency and governance gap: an agent or reviewer cannot easily tell that local files, API keys, and uploaded images may be accessed or transmitted to third-party services.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases include broad terms like "generate 3D" and "convert to 3D model," which are likely to match many generic user requests beyond this skill's intended scope. Over-broad activation can cause the skill to run unexpectedly, increasing the chance that user images are sent to external services or files are created without clear user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill description explains the pipeline but does not warn users that their input images are transmitted to external AI providers (Gemini and Tripo3D). This is a meaningful privacy and data-handling issue because users may provide sensitive, proprietary, or personal images without understanding that third-party services will process them.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 73)May include surrounding context.

python
},
    }

    resp = requests.post(url, json=payload, timeout=120)
    if resp.status_code != 200:
        print(f"❌ Gemini API 错误: {resp.status_code}")
        print(resp.text[:500])

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script uploads user images to external Gemini and Tripo3D services, but there is no explicit consent prompt or prominent warning that local images are transmitted to third parties. In a photo-processing skill, this matters because users may assume processing is local and may unknowingly send sensitive images off-device.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 119)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 140)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 120)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},
            timeout=60,

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 141)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},
            timeout=60,

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 166)May include surrounding context.

python
img_path = Path(image_path)
    with open(img_path, "rb") as f:
        upload_resp = requests.post(
            "https://api.tripo3d.ai/v2/openapi/upload",
            headers=headers,
            files={"file": (img_path.name, f, "image/png")},
            timeout=60,

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 140)May include surrounding context.

python
print(f"  📤 图片已上传, token: {image_token[:20]}...")

    # 创建 image-to-3d 任务
    task_resp = requests.post(
        "https://api.tripo3d.ai/v2/openapi/task",
        headers={**headers, "Content-Type": "application/json"},
        json={"type": "image_to_model", "file": {"type": "png", "file_token": image_token}},

Tainted flow: 'task_id' from requests.post (line 153, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 165)May include surrounding context.

python
start = time.time()
    while time.time() - start < max_wait:
        time.sleep(5)
        status_resp = requests.get(
            f"https://api.tripo3d.ai/v2/openapi/task/{task_id}",
            headers=headers,
            timeout=30,

Tainted flow: 'model_url' from requests.get (line 179, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
91% confidence
Finding

The code fetches model_url directly from a remote API response and immediately performs requests.get on it without validating the hostname, scheme, or content type. If the upstream service is compromised or returns an unexpected URL, this could trigger server-side request forgery to arbitrary destinations or download untrusted content to disk.

Content

Scanner excerpt · scripts/photo_to_3d.py (reported line 182)May include surrounding context.

python
model_url = status_data.get("output", {}).get("model", "")
            if model_url:
                output_path = OUTPUT_DIR / f"{img_path.stem}_model.glb"
                model_resp = requests.get(model_url, timeout=120)
                output_path.write_bytes(model_resp.content)
                print(f"  📦 模型已保存: {output_path}")
                return str(output_path)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The file's natural-language strings and user-facing interface are entirely in Chinese, with no indication that language is selectable or intentionally limited to a specific audience. This can violate language/locale policy when a skill imposes a language without user opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.