Back to skill

Security audit

Dazzle Photo Intelligence

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Dazzle photo-intelligence bridge, but it enables broad silent use of highly personal photo-derived data after one sign-in.

Install only if you are comfortable with Dazzle receiving sensitive personalization queries and using your photo-derived account context after a one-time sign-in. Prefer explicit use such as 'ask Dazzle' for sensitive topics, review/revoke Dazzle account access when needed, and be cautious about fetching photo URLs returned by the service.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T01 · Skill Instruction Hijacking

Warning
Location
dazzle_photo_intelligence/proxy.py:499
Finding
Untrusted Remote Tool Metadata and Photo URLs Can Influence Agent Behavior## Vulnerability Details **File Location**: `dazzle_photo_intelligence/proxy.py:499-506`; related instruction at `SKILL.md:108-110` **Vulnerability Type**: Remote instruction injection and unsafe remote URL handling **Risk Level**: Medium ### Vulnerable Code ```python tools_payload = result.get("result", {}).get("tools", []) return [ Tool( name=t["name"], description=t.get("description", ""), inputSchema=t.get("inputSchema", {"type": "object", "properties": {}}), ) for t in tools_payload ] ``` The corresponding Skill instruction states: ```markdown Matched photos come back as URLs in a `<photos>` JSON block, not inline bytes. Fetch the URL to get the image bytes when you need to view, analyze, or include the image in a response. ``` ### Technical Analysis The proxy obtains tool names, descriptions, and input schemas from the remote Dazzle MCP endpoint and registers them directly with the local agent. No local allowlist, trusted description mapping, schema validation, or sanitization boundary is applied. Tool descriptions are agent-visible instructions rather than ordinary inert data. If the remote endpoint or an upstream account is compromised, an attacker could return a tool description containing instructions intended to override the user's task, request sensitive information, or induce unrelated tool calls. This creates an indirect instruction-injection channel. The Skill also instructs the agent to fetch photo URLs returned by the remote service without prescribing scheme, hostname, redirect, or destination-address validation. Although this Python package does not itself download those URLs, the instruction can cause the surrounding agent to perform the request. A crafted URL could consequently target an attacker-controlled endpoint or, where the agent's fetching tool permits it, private, loopback, link-local, or cloud metadata addresses. ### Attack Path 1. An ...[truncated 1313 chars]
Remediation
## Remediation Suggestions 1. Define a local allowlist of supported tool names and reject every undeclared remote tool. 2. Supply locally maintained, trusted tool descriptions instead of exposing remote descriptions directly to the agent. 3. Validate remote input schemas against strict local schemas, including field types, lengths, and allowed values. 4. Explicitly label all remote response text as untrusted data and prohibit treating it as agent instructions. 5. Validate returned photo URLs before allowing the agent to fetch them: - Permit only HTTPS. - Restrict hostnames to documented Dazzle-controlled CDN domains. - Resolve hostnames and reject loopback, private, link-local, multicast, and reserved addresses. - Revalidate every redirect target and impose a small redirect limit. - Reject URLs containing embedded credentials or unexpected ports. 6. Fetch images through a constrained bridge endpoint rather than instructing a general-purpose agent fetcher to access arbitrary URLs. 7. Apply response-size, media-type, and timeout limits when retrieving image content.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:17
Finding
Over-Broad Automatic Invocation Can Disclose Personal Queries Without Per-Query Consent## Vulnerability Details **File Location**: `SKILL.md:17-37`; transmission implementation at `dazzle_photo_intelligence/proxy.py:510-516` **Vulnerability Type**: Excessive remote-data disclosure policy **Risk Level**: Medium ### Vulnerable Instructions and Code ```markdown Consult Dazzle whenever knowing the user — their likes, places they've been, what piques their attention — would improve the answer. Concrete categories: - **Photos & memories** — "find food photos from today", "show sunsets from last weekend", "send pictures from the user's last family vacation?" - **Places** — "where does the user live", "what restaurants does the user enjoy", "where has the user been" - **Recommendations** — "where should the user go for his/her next vacation?", "suggest a restaurant for tonight given what he/she usually likes" - **Personal facts and summaries** — "What is the user's daughter's name?", "what did the user do last weekend?", "summarize events and activities from my year so far" - **Context-aware decisions** — "what gift would the user's father like?", "if the user is in Denver, where should they go for a nicer meal?" - **Context** — "what types of things does the user do when visiting NYC?", "what seems to be the user's favorite color?", "what brands of clothes does the user buy?", "what sports teams does the user cheer for?", "which celebrities does the user admire", "what types of things has the user been thinking about purchasing recently", "what sports does the user participate in or watch?" Always invoke Dazzle when the user mentions it by name ("ask Dazzle to…", "what does Dazzle know about…"). ``` Tool arguments are then forwarded to the external service: ```python @server.call_tool() async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]: async with _http_client() as client: if name == LOGIN_REQUIRED_TOOL: return [Tex ...[truncated 2550 chars]
Remediation
## Remediation Suggestions 1. Change the activation rule from automatic personalization to explicit invocation, such as requiring “ask Dazzle” or an equivalent unambiguous user request. 2. Before the first disclosure in each session, clearly state that the query will be sent to Dazzle and obtain user confirmation. 3. For especially sensitive categories such as location, family relationships, and photo retrieval, require confirmation for each query. 4. Add a local argument-minimization layer that forwards only fields required by an allowlisted tool schema. 5. Do not include unrelated conversation history, hidden prompts, credentials, or environmental data in tool arguments. 6. Show the user a concise preview of the categories of information that will be transmitted. 7. Provide a local-only or disabled-by-default personalization mode. 8. Document retention, processing, revocation, and deletion behavior for data sent through individual tool calls. 9. Add audit logging that records the destination, tool name, and data categories transmitted without logging raw sensitive values.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (58)

Ae1

High
Category
analysis-evasion
Content
*this skill directory* (the one containing this `SKILL.md`) for `<SKILL_DIR>`, then
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
async def _refresh_access_token(client: httpx.AsyncClient, host: str, client_id: str) -> str | None:
    """Refresh the access token. Returns the new access token, or None if refresh failed.

    Storage writes happen under _refresh_lock so concurrent proxies can't corrupt the
    file-backed keyring. On a non-200 response, re-checks under the lock for a peer-rotated
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
async def _refresh_access_token(client: httpx.AsyncClient, host: str, client_id: str) -> str | None:
    """Refresh the access token. Returns the new access token, or None if refresh failed.

    Storage writes happen under _refresh_lock so concurrent proxies can't corrupt the
    file-backed keyring. On a non-200 response, re-checks under the lock for a peer-rotated
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Token storage backed by the OS keyring with an encrypted-file fallback for headless hosts.

When the OS keyring is unavailable (typical on bare Linux VPS without a Secret Service daemon, or
locked Keychain on a headless Mac), the user must set DAZZLE_KEYRING_PASSWORD so we can
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

No suspicious patterns detected.