T09 · Insecure Skill Coding Practices
- Location
scripts/gws_wrapper.py:8- Finding
API Key Transmitted to an Unrestricted Runtime-Configured Endpoint
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill appears intended to manage Google Workspace, but it handles credentials and high-impact Google actions with too little scoping and guardrail detail.
Review this skill before installing. Only use it if you trust MyBrandMetrics and the local gws CLI, set GWS_TOKEN_URL only to the official HTTPS token service, protect the API key file with restrictive permissions, and require explicit user confirmation before delete, trash, move, overwrite, or sharing-permission changes.
scripts/gws_wrapper.py:8API Key Transmitted to an Unrestricted Runtime-Configured Endpoint
scripts/install_gws.sh:5Unpinned and Integrity-Unverified Installation of an Executable Dependency
SKILL.md:67Plaintext API-Key File Created Without Enforced Restrictive Permissions
The code sends the API key in a custom header to a URL taken directly from the GWS_TOKEN_URL environment variable without any allowlisting or validation. If that environment variable is altered, secrets can be exfiltrated to an attacker-controlled endpoint and a malicious token can be returned for later use.
data = {"source_key": source_key}
try:
response = requests.post(TOKEN_URL, headers=headers, json=data)
response.raise_for_status()
return response.json().get("access" + "_token")
except Exception as e:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| --- | --- |
| Sign in to MyBrandMetrics with Google. | Create or configure a Google Cloud project. |
| Connect Google Calendar, Google Drive, and Google Sheets as data sources. | Configure OAuth clients, scopes, and local MCP server auth. |
| Use a MyBrandMetrics API key to fetch managed access tokens. | Manage credentials and token storage yourself. |
| Run with a local wrapper around `gws`; no MCP server required. | Requires running and maintaining an MCP server. |
Use this when you want Google Workspace actions without setting up your own
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| --- | --- |
| Sign in to MyBrandMetrics with Google. | Create or configure a Google Cloud project. |
| Connect Google Calendar, Google Drive, and Google Sheets as data sources. | Configure OAuth clients, scopes, and local MCP server auth. |
| Use a MyBrandMetrics API key to fetch managed access tokens. | Manage credentials and token storage yourself. |
| Run with a local wrapper around `gws`; no MCP server required. | Requires running and maintaining an MCP server. |
Use this when you want Google Workspace actions without setting up your own
Copying the full parent environment into a child process is not inherently malicious, but it increases the blast radius of any compromised or trojaned gws binary by exposing all inherited environment secrets in addition to the access token. In this skill, that risk is amplified because the subprocess is an external CLI whose path may be influenced by the local environment.
token = get_token(source_key, api_key)
# Prepare environment
env = os.environ.copy()
env["GOOGLE_WORKSPACE_CLI_TOKEN"] = token
# Execute gws
The skill advertises capabilities that imply shell, network, environment, and file access, but it does not declare any explicit tool scope or permissions boundaries. This creates an over-privileged integration pattern where an agent may invoke sensitive local or networked operations without clear least-privilege constraints, increasing the risk of unintended command execution, local file access, or exfiltration.
The skill supports destructive actions such as deleting calendar events, deleting or trashing Drive files, moving files, and modifying sharing permissions, but it does not prominently warn users or require confirmation before those operations. In an agent-driven workflow, missing guardrails around destructive actions can lead to accidental data loss or unauthorized sharing from ambiguous natural-language prompts.
This file transmits sensitive material off-host: the MyBrandMetrics API key is sent over the network to obtain an access token. External transmission is part of the intended design, but it remains security-sensitive because compromise of the destination or misconfiguration of the URL exposes credentials.
data = {"source_key": source_key}
try:
response = requests.post(TOKEN_URL, headers=headers, json=data)
response.raise_for_status()
return response.json().get("access" + "_token")
except Exception as e:
The wrapper resolves gws by calling which via PATH and, if found, later executes gws by name. In a compromised or attacker-controlled environment, PATH hijacking could cause a malicious which or gws binary to be executed, inheriting the freshly obtained access token via environment variables.
try:
# Check if gws is in PATH, if not try the local scripts dir
if subprocess.call(["which", "gws"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) != 0:
local_gws = os.path.join(os.path.dirname(__file__), "gws_musl")
if os.path.exists(local_gws):
cmd[0] = local_gws
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if os.path.exists(local_gws):
cmd[0] = local_gws
result = subprocess.run(cmd, env=env, capture_output=False)
sys.exit(result.returncode)
except Exception as e:
print(f"Error executing gws: {e}", file=sys.stderr)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Fallback: attempt to download latest release binary if go is missing
echo "Go not found. Attempting to download compatible musl binary..."
# We target the musl version specifically for better portability on older/different glibc environments
VERSION=$(curl -s https://api.github.com/repos/googleworkspace/cli/releases/latest | grep "tag_name" | cut -d : -f 2 | tr -d \"\ ,)
FILENAME="google-workspace-cli-x86_64-unknown-linux-musl.tar.gz"
URL="https://github.com/googleworkspace/cli/releases/download/${VERSION}/${FILENAME}"
No suspicious patterns detected.