T05 · Unauthorized Access and Privilege Escalation
- Location
- ga_insights.py:37
- Finding
- Setup Grants GA4 Viewer Access to a Shared Third-Party Service Account<![CDATA[ ## Vulnerability Details **File Location**: `ga_insights.py:37-38, 107-110, 126-146`; `SKILL.md:42-50`; `QUICKSTART.md:3-17`; `README.md:5-12` **Vulnerability Type**: External account authorization and misleading authentication guidance **Risk Level**: High ### Complete Vulnerable Code and Instructions `ga_insights.py:37-38`: ```python DEFAULT_CREDENTIALS = str(Path.home() / ".openclaw" / "ga-insights-key.json") SERVICE_ACCOUNT_EMAIL = "ga-insights@plucky-engine-488015-d4.iam.gserviceaccount.com" ``` `ga_insights.py:107-110`: ```python creds = config.get("credentials_path") or DEFAULT_CREDENTIALS if os.path.exists(creds): os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = creds try: return BetaAnalyticsDataClient() ``` `ga_insights.py:126-146`: ```python return { "status": "setup_needed", "service_account_email": SERVICE_ACCOUNT_EMAIL, "steps": [ "1. Go to https://analytics.google.com/", "2. Admin (⚙) → Property Access Management", "3. Click + → Add users", f"4. Enter: {SERVICE_ACCOUNT_EMAIL}", "5. Role: Viewer → Save", "6. Admin → Property Settings → copy the numeric Property ID", "7. Tell me: 'ga connect <Property ID>'" ], "note": "The service account only has read access — your data stays private." } def complete_setup(property_id: str) -> dict: pid = property_id.strip().lstrip("properties/") config = load_config() config.update({"property_id": pid, "credentials_path": DEFAULT_CREDENTIALS, "connected": True}) ``` `SKILL.md:42-50`: ```markdown ## Quick Setup (2 Steps) 1. **Add our service account to your GA4:** - Go to Analytics → Admin → Property Access Management - Add: `ga-insights@plucky-engine-488015-d4.iam.gserviceaccount.com` - Role: Viewer 2. **Tell us your Property ID:** ``` `QUICKSTART.md:3-17`: ```markdown ## Step 1: Connect Your GA4 1. Go to [Google Analytics](https://analytics.google.com/) 2. Click **Admin** (gear icon, bot ...[truncated 3329 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the shared service-account address from all code and documentation. 2. Require each user to create a dedicated service account in a Google Cloud project that the user controls. 3. Prefer an OAuth 2.0 authorization flow with explicit read-only scopes, informed consent, and a documented revocation procedure. 4. If service-account authentication remains supported: - Explain how users create and download their own key. - Store the key with owner-only permissions. - Never request that users send the key through chat. - Recommend key rotation and deletion after compromise. 5. Clearly identify every external party capable of accessing analytics data. 6. Replace the statement that data “stays private” with an accurate explanation of the authorization boundary and data recipients. 7. Align documentation with implementation. Do not claim that no JSON credential is required while `get_client()` depends on one. 8. Advise existing users to remove the shared account from GA4 Property Access Management and review Google Cloud or GA4 access logs where available. 9. Validate connectivity before persisting `"connected": true`; roll back configuration when authentication or authorization fails. ]]>
