Back to skill

Security audit

Google ads for OpenClaw

Security checks for vulnerabilities and agentic risk

Overview

This Google Ads skill is not malicious, but it handles sensitive ad-account credentials and account selection too loosely for a business-impacting integration.

Install only if you are comfortable with an agent reading your local Google Ads credential configuration. Before using it, restrict ~/.google-ads.yaml permissions to owner-only, avoid storing real secrets in shared workspaces, and require explicit confirmation of the target Google Ads customer account before any operation. Treat the advertised budget/status features as incomplete in this artifact.

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/setup_ads.py:4
Finding
Google Ads Credential File Is Created Without Restrictive Permissions## Vulnerability Details **File Location**: `scripts/setup_ads.py`, lines 4–12 **Vulnerability Type**: Insecure permissions on a sensitive configuration file **Risk Level**: Medium ### Vulnerable Code ```python def create_config_template(path): config = { 'developer_token': 'INSERT_DEVELOPER_TOKEN_HERE', 'client_id': 'INSERT_CLIENT_ID_HERE', 'client_secret': 'INSERT_CLIENT_SECRET_HERE', 'refresh_token': 'INSERT_REFRESH_TOKEN_HERE', 'use_proto_plus': True } with open(path, 'w') as f: yaml.dump(config, f, default_flow_style=False) ``` ### Technical Analysis The script creates `~/.google-ads.yaml` with Python's standard `open(path, 'w')` operation and does not explicitly enforce owner-only permissions. The resulting permissions therefore depend on the process umask. For example, a typical umask of `022` can produce a file with mode `0644`, making it readable by other local users. The file initially contains placeholders, but its intended purpose is to store a Google Ads developer token, OAuth client secret, and refresh token. After a user replaces the placeholders with real credentials, permissive file permissions can expose those secrets to other accounts on the same system. ### Attack Path 1. The user runs `scripts/setup_ads.py`. 2. The script creates `~/.google-ads.yaml` without explicitly setting mode `0600`. 3. The user inserts valid Google Ads credentials into the generated file. 4. On a multi-user host with a permissive umask, another local account reads the configuration file. 5. The attacker extracts the developer token, client credentials, and refresh token. 6. The attacker attempts to reuse those credentials through the Google Ads API. Exploitation requires local filesystem access under an account permitted to read the resulting file. Actual API access remains constrained by the validity, authorization scope, and account permissions o ...[truncated 622 chars]
Remediation
## Remediation Suggestions Create the credential file atomically with owner-only permissions and refuse to overwrite an existing file: ```python import os import yaml def create_config_template(path): config = { 'developer_token': 'INSERT_DEVELOPER_TOKEN_HERE', 'client_id': 'INSERT_CLIENT_ID_HERE', 'client_secret': 'INSERT_CLIENT_SECRET_HERE', 'refresh_token': 'INSERT_REFRESH_TOKEN_HERE', 'use_proto_plus': True, } flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL fd = os.open(path, flags, 0o600) try: with os.fdopen(fd, 'w') as f: yaml.safe_dump(config, f, default_flow_style=False) except Exception: try: os.unlink(path) except OSError: pass raise ``` Additional hardening measures: - Verify the final mode with `os.stat()` and reject or correct group/world-readable permissions. - Apply `os.chmod(path, 0o600)` where appropriate as a defense-in-depth measure. - Warn users that the file contains sensitive credentials and must not be committed to source control. - Prefer a platform credential store or secrets manager where operationally feasible. - Rotate the refresh token, client secret, and developer token if unauthorized file access is suspected.
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 (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the skill claims to manage Google Ads but in reality only creates a local configuration file containing credential parameters, that is a meaningful security concern. It can mislead the agent or user into handling sensitive secrets locally under the guise of API operations, increasing the risk of accidental credential exposure or improper storage.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the skill claims to manage Google Ads but in reality only creates a local configuration file containing credential parameters, that is a meaningful security concern. It can mislead the agent or user into handling sensitive secrets locally under the guise of API operations, increasing the risk of accidental credential exposure or improper storage.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Lp3

Medium
Category
MCP Least Privilege
Confidence
72% confidence
Finding
The skill instructs the agent to rely on a local configuration file and references a script that can modify campaign state, yet it does not declare any explicit tool scope or permission boundaries. In an agent environment, missing scope declarations can lead to broader-than-intended file access or write operations, especially around credential files like ~/.google-ads.yaml.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The natural-language content of the skill, including the manifest description and all usage instructions, is entirely in Russian, which can impose a language choice on users or agents without offering an alternative or opt-in. The file does not document that this skill is intended only for a Russian-speaking or region-specific environment, so this creates a language/locale policy concern.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest says the skill can change budgets and enable or disable campaigns through the Google Ads API. Although CLI subcommands for `update-status` and `update-budget` are declared, the only implemented behavior in the command handler is the `list` branch, so no modifying operations actually occur.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The tool silently loads Google Ads credentials from the default local configuration, which can cause it to operate against whichever account is present on the host without explicit user awareness or account selection. In an agent/skill context, this increases the risk of unintended access to sensitive advertising data and actions being performed under the wrong account.

Static analysis

No suspicious patterns detected.