Back to skill

Security audit

Google Maps

Security checks for vulnerabilities and agentic risk

Overview

This Google Maps skill mostly does what it advertises, but it can print your Google API key inside returned place photo URLs.

Review before installing. Use a Google API key restricted to only the required Maps APIs, with quota and billing limits, and rotate it if this skill has already printed search/details results containing photo_url fields. Avoid sensitive home, work, medical, legal, or client locations unless you are comfortable sending them to Google. The publisher should fix the skill so it never returns API keys in URLs and should add clearer privacy disclosure for location data.

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
lib/map_helper.py:259
Finding
Google Maps API Key Disclosed in Returned Photo URLs<![CDATA[ ## Vulnerability Details **File Location**: `lib/map_helper.py:254-260` and `lib/map_helper.py:278-283` **Vulnerability Type**: Sensitive credential exposure in application output **Risk Level**: Medium ### Vulnerable Code ```python results = res.get("results", [])[:5] for place in results: if place.get("photos"): photo_ref = place["photos"][0]["photo_reference"] place["photo_url"] = f"https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference={photo_ref}&key={self.api_key}" return results ``` ```python res = requests.get(url, params=params).json().get("result", {}) if res.get("photos"): photo_ref = res["photos"][0]["photo_reference"] res["photo_url"] = f"https://maps.googleapis.com/maps/api/place/photo?maxwidth=800&photoreference={photo_ref}&key={self.api_key}" return res ``` The resulting objects are subsequently printed to standard output: ```python print(json.dumps(result, ensure_ascii=False, indent=2)) ``` ### Technical Analysis The `search` and `details` operations construct photo URLs containing `self.api_key` as a query parameter and return those URLs as part of their normal output. Because the complete result is serialized to standard output, the credential can be propagated into agent responses, command logs, shell captures, telemetry, chat histories, or downstream integrations. Transmitting the API key directly to Google's authenticated API endpoints is necessary for the declared mapping functionality. Returning that key to the caller in a generated URL is not necessary and exceeds the minimum disclosure required for the task. Although HTTPS protects the URL while it is sent to Google, it does not prevent disclosure through application output, logging, browser history, referrer metadata, screenshots, or other systems that process the returned JSON. ### Attack Path 1. A user configures the Skill with a valid `GOOGLE_API_KEY` or `GOOGLE_MAPS_API_KEY`. 2. The attacker causes the user ...[truncated 1208 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not include API keys in returned URLs or serialized application output. 2. Return the photo reference instead of an authenticated URL, for example: ```python place["photo_reference"] = photo_ref ``` 3. If callers require the photo itself, retrieve it server-side and return the image data or a locally controlled short-lived reference without exposing the Google credential. 4. Add output sanitization that removes sensitive query parameters such as `key`, `token`, and `signature` before serialization or logging. 5. Ensure exception handlers and HTTP debugging facilities do not log authentication headers, request URLs containing keys, or full response objects carrying generated credential-bearing URLs. 6. Restrict the Google API key to only the required Google Maps APIs. Where supported, apply application, source-IP, HTTP-referrer, or service-account restrictions. 7. Configure conservative quotas and billing alerts. 8. Rotate the existing key if outputs from `search` or `details` may already have entered logs, telemetry, or chat histories. 9. Add automated tests asserting that command output never contains the configured API key. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:20
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:20-24` **Vulnerability Type**: Unpinned dependency and non-reproducible installation **Risk Level**: Low ### Vulnerable Documentation ```markdown ## Requirements - `GOOGLE_API_KEY` environment variable - Enable in Google Cloud Console: Routes API, Places API, Geocoding API - Python package: `requests` (`pip install requests`) ``` ### Technical Analysis The documentation instructs users to install `requests` without an exact version, dependency lock file, or integrity hashes. This causes pip to resolve mutable package and transitive-dependency versions from the configured package index at installation time. The package name is legitimate, and the reviewed project contains no evidence of dependency confusion, typosquatting, or a malicious package source. Nevertheless, an unpinned installation is non-reproducible and automatically trusts future releases and dependency-resolution results that were not part of this audit. ### Attack Path 1. A user follows the documented `pip install requests` instruction. 2. pip queries the user's configured package index and resolves the latest compatible release and transitive dependencies. 3. A future compromised release, compromised package-index response, or malicious package supplied through an untrusted configured index is selected. 4. The package is installed into the user's environment. 5. Malicious installation or runtime code executes with the privileges of the user or service running the installation and Skill. This path requires a supply-chain compromise, unsafe package-index configuration, or another manipulation of dependency resolution; the audited source itself does not introduce a malicious dependency. ### Impact Assessment If dependency resolution is compromised, malicious package code could execute with the privileges of the installing user or the account running the Skill. Potential consequences include: - Reading environment variables, i ...[truncated 391 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a reviewed dependency lock file containing exact versions for `requests` and its transitive dependencies. 2. Include cryptographic hashes and install with hash verification, for example: ```bash python -m pip install --require-hashes -r requirements.txt ``` 3. Generate the lock file from a trusted package index in a controlled environment. 4. Document the expected package index and discourage installation from unknown mirrors. 5. Periodically scan locked dependencies for known vulnerabilities and update them through a reviewed process. 6. Run installation and the Skill under a dedicated, least-privileged account or isolated virtual environment. 7. Avoid granting the runtime environment access to unrelated credentials or sensitive files. ]]>
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 (14)

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'env' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'network' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Forward geocoding sends user-supplied addresses to Google, which can disclose sensitive location information to a third party without any explicit notice or consent flow in the skill path. In a mapping skill this data transfer is expected, but the absence of disclosure still creates a real privacy risk because addresses may reveal home, work, or other sensitive places.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Reverse geocoding transmits precise latitude/longitude, which is highly sensitive and can identify exact user whereabouts. Without explicit disclosure or consent, the skill may expose precise location data to an external provider in ways users do not expect.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Place search sends free-text queries plus optional location context to Google, which can reveal user interests, habits, and nearby position. In-context this is core functionality, but the lack of disclosure means users may unknowingly share sensitive contextual data with a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
"X-Goog-FieldMask": "routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs.startLocation,routes.legs.endLocation"
        }
        
        response = requests.post(url, headers=headers, json=request_body)
        
        if response.status_code != 200:
            return {"error": f"API error: {response.status_code}", "details": response.text}
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"X-Goog-FieldMask": "routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs.startLocation,routes.legs.endLocation"
        }
        
        response = requests.post(url, headers=headers, json=request_body)
        
        if response.status_code != 200:
            return {"error": f"API error: {response.status_code}", "details": response.text}
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"X-Goog-FieldMask": "routes.duration,routes.staticDuration,routes.distanceMeters,routes.legs.startLocation,routes.legs.endLocation"
        }
        
        response = requests.post(url, headers=headers, json=request_body)
        
        if response.status_code != 200:
            return {"error": f"API error: {response.status_code}", "details": response.text}
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Route computation sends origin, destination, timing, and routing preferences to Google, which can expose travel plans and sensitive personal patterns. Because this skill is specifically built for navigation, the transmission is contextually expected, but lack of clear disclosure and consent still makes it a genuine privacy weakness.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Detailed directions requests may include origin, destination, waypoints, departure/arrival times, and transit details, creating an even richer picture of a user's movements and intent. This makes the privacy concern stronger than basic lookups if users are not clearly informed that this data is sent off-platform to Google.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Route matrix requests can transmit multiple origins and destinations in one call, potentially exposing a broader set of locations such as offices, homes, clients, or planned stops. The bulk nature of the request increases privacy sensitivity, and the code offers no user-facing notice before sending this data externally.

Missing User Warnings

Low
Confidence
85% confidence
Finding
Place details sends a place identifier to Google; this is less sensitive than raw coordinates or free-text addresses, but it still discloses what place the user is interested in. The privacy impact is lower, yet a disclosure gap remains.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The manifest advertises distance/travel-time calculations with traffic prediction and avoid options, and the module documentation presents matrix support as part of the Routes API feature set. In the matrix method, departure_time is parsed and then explicitly discarded, and avoid is accepted in the signature but never used, so the implemented behavior falls short of the described capability.

Intent-Code Divergence

Low
Confidence
79% confidence
Finding
The help text shows `matrix ... [options]`, which in context suggests the same option style described above, including departure time and avoid settings. However, the matrix implementation does not apply `avoid` at all and deliberately ignores parsed `departure_time`, so the documentation overstates what the command actually does.

Static analysis

No suspicious patterns detected.