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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
*this skill directory* (the one containing this `SKILL.md`) for `<SKILL_DIR>`, then

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 192)May include surrounding context.

python
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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 238)May include surrounding context.

python
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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 1)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 11)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 67)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/proxy.py (reported line 195)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 1)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 3)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 5)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 17)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 18)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 32)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 36)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 45)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 47)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 50)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 51)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 55)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 60)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 63)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 67)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 70)May include surrounding context.

python
"""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

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dazzle_photo_intelligence/storage.py (reported line 77)May include surrounding context.

python
"""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