Back to skill

Security audit

Google Colab GPU Runtime

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its Colab GPU purpose, but it handles reusable Google and ElevenLabs credentials in ways that users should review carefully before installing.

Install only if you are comfortable granting Colab and Drive access, transmitting code and possibly credentials to Colab runtimes, and using ElevenLabs for voice-related data. Prefer a dedicated Google account/project, revoke or rotate tokens after use, avoid passing real API keys as command-line arguments, and review scripts before using inject_and_run.sh with Drive access.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/inject_and_run.sh:13
Finding
Reusable OAuth Credential Injected into Remote Colab Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/inject_and_run.sh:13-29` **Additional Locations**: `SKILL.md:56-69`, `references/examples.md:34-41` **Vulnerability Type**: Reusable OAuth credential exposure through remote source injection **Risk Level**: High ### Vulnerable Code ```bash TOKEN_B64=$(python3 -c " import base64, os with open(os.path.expanduser('~/.colab-mcp-auth-token.json')) as f: print(base64.b64encode(f.read().encode()).decode()) ") # Create temp script with token injected (restricted permissions) TMPSCRIPT=$(mktemp /tmp/colab_XXXXX.py) chmod 600 "$TMPSCRIPT" # Always clean up the token-bearing temp file cleanup() { rm -f "$TMPSCRIPT"; } trap cleanup EXIT INT TERM sed "s|__COLAB_TOKEN_PLACEHOLDER__|${TOKEN_B64}|" "$SCRIPT" > "$TMPSCRIPT" # Run on Colab SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" python3 "$SCRIPT_DIR/colab_run.py" exec --file "$TMPSCRIPT" "$@" ``` The documented remote-side usage decodes and writes the credential: ```python TOKEN_B64 = "__COLAB_TOKEN_PLACEHOLDER__" token_data = json.loads(base64.b64decode(TOKEN_B64)) with open('/tmp/token.json', 'w') as f: json.dump(token_data, f) creds = Credentials.from_authorized_user_file('/tmp/token.json') service = build('drive', 'v3', credentials=creds) ``` ### Technical Analysis The script reads the complete local `~/.colab-mcp-auth-token.json` file, Base64-encodes it, substitutes it into Python source code, and submits that source to a remote Google Colab runtime. Base64 is a transport encoding and provides no confidentiality. The credential file may include both access and refresh tokens. Consequently, the remote runtime receives a reusable account credential rather than a narrowly delegated, short-lived capability. The credential may also cover identity, Colab, and Drive scopes. This exceeds the minimum privilege needed when a remote task only needs to read or write a specific checkpoint. The local temporary script is assigned mode `0600` and remo ...[truncated 1636 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not embed refresh-token-bearing OAuth credential files in notebook source code. 2. Use short-lived, task-specific credentials that cannot be refreshed and are restricted to the minimum required resource and operation. 3. Prefer a brokered upload/download design where Drive operations remain local and only required files are transferred to the runtime. 4. If remote Drive access is unavoidable, use the supported Colab authentication workflow or a dedicated service identity with narrowly scoped permissions. 5. Separate Colab authorization from Drive authorization so a remote task does not receive unrelated account privileges. 6. Create any remote credential file with mode `0600`, avoid predictable locations, and delete it in a `finally` block immediately after credentials are loaded. 7. Prevent credentials from appearing in source, notebook history, kernel output, exceptions, logs, or diagnostic dumps. 8. Revoke and rotate any OAuth credentials that may already have been transmitted to untrusted runtimes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/colab_run.py:166
Finding
Sensitive OAuth and Runtime State Files Lack Explicit Permission Enforcement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/colab_run.py:166-176` **Additional Location**: `scripts/reauth_with_drive.py:70-72` **Vulnerability Type**: Insecure storage of sensitive local credentials and runtime tokens **Risk Level**: Medium ### Vulnerable Code The runtime state includes the remote proxy token and is written using the process's default creation permissions: ```python def save_state(self): """Save runtime state for later resume.""" state = { "endpoint": self.endpoint, "proxy_url": self.proxy_url, "proxy_token": self.proxy_token, "notebook_id": str(self.notebook_id), } with open(STATE_PATH, "w") as f: json.dump(state, f) ``` The OAuth reauthentication script similarly writes the complete credential without explicitly enforcing restrictive permissions: ```python # Save updated token with open(TOKEN_PATH, "w") as f: f.write(creds.to_json()) ``` ### Technical Analysis Both files contain security-sensitive bearer material: - `~/.colab-runtime-state.json` contains `proxy_token`, which is used when connecting to the active Jupyter kernel. - `~/.colab-mcp-auth-token.json` may contain Google OAuth access and refresh tokens. Opening these paths with ordinary `open(..., "w")` relies on the current process umask and existing file permissions. If a file is newly created under a permissive umask, it may be readable by other local users. If an existing file already has unsafe permissions, truncating and rewriting it does not correct those permissions. The code also does not verify file ownership, reject symbolic links, or use atomic replacement. In a hostile shared environment, this creates additional opportunities for unintended disclosure or path manipulation. ### Attack Path 1. The Skill runs under an account with a permissive umask, or the sensitive file already has overly broad permissions. 2. `save_state()` or the reauthentication script writes a proxy token or O ...[truncated 843 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create credential and state files explicitly with mode `0600`. 2. Validate that existing files are owned by the current user and are not readable or writable by group or other users. 3. Reject symbolic links by using `O_NOFOLLOW` where supported. 4. Write to a securely created temporary file in the same directory, call `fsync`, set mode `0600`, and atomically replace the destination. 5. Ensure the parent directory is owned by the user and is not writable by untrusted accounts. 6. Remove stale runtime state immediately when a runtime is stopped or no longer valid. 7. Avoid storing the proxy token when runtime resume is not requested. 8. Add startup checks that warn or abort when existing token files have unsafe permissions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/colab_tts.py:225
Finding
ElevenLabs API Key Accepted Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/colab_tts.py:225-226` **Additional Locations**: `scripts/colab_tts.py:15`, `SKILL.md:76` **Vulnerability Type**: Secret exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```python p_fetch = sub.add_parser("fetch-voice", help="Download voice samples from ElevenLabs") p_fetch.add_argument("--voice-id", required=True) p_fetch.add_argument("--api-key", required=True) ``` The documented invocation encourages users to place the key directly on the command line: ```bash python3 colab_tts.py fetch-voice --voice-id YOUR_VOICE_ID --api-key YOUR_API_KEY ``` The key is subsequently used as an ElevenLabs authentication header: ```python headers = {"xi-api-key": api_key} resp = requests.get( f"https://api.elevenlabs.io/v1/voices/{voice_id}", headers=headers ) ``` ### Technical Analysis Command-line arguments are not a safe secret-delivery mechanism. Depending on the operating system and environment, process arguments may be visible to other local users through process inspection, monitoring agents, crash reports, audit tooling, or diagnostic collection. Literal commands are also commonly retained in shell history. The network use itself is consistent with the declared feature: the key is sent in an authentication header to the HTTPS ElevenLabs API. No unrelated destination was identified. The vulnerability is the local handling and documentation of the secret, not covert network exfiltration. ### Attack Path 1. A user follows the documented command and supplies a real ElevenLabs API key through `--api-key`. 2. The shell records the command in its history, or the argument remains visible while the process is running. 3. Another local user, support bundle, monitoring process, or later history reader obtains the key. 4. The attacker submits requests to ElevenLabs using the stolen key. ### Impact Assessment An attacker with the exposed key may consu ...[truncated 312 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove or deprecate the `--api-key` command-line option. 2. Read the key from a protected environment variable, a restricted configuration file, an operating-system credential store, or a file descriptor. 3. If no secure source is configured, prompt interactively using `getpass.getpass()`. 4. Update all documentation so examples never place literal secrets in command arguments. 5. Ensure errors and debug logs do not print request headers or the supplied key. 6. Encourage users to configure narrowly scoped keys where the provider supports them. 7. Rotate any API key that has previously been entered in shell commands or stored in shared command history. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/colab_run.py:39
Finding
Unpinned Third-Party Packages Installed Automatically at Runtime<![CDATA[ ## Vulnerability Details **File Location**: `scripts/colab_run.py:39-47` **Additional Location**: `scripts/colab_tts.py:91-97` **Vulnerability Type**: Unverified mutable dependency retrieval and execution **Risk Level**: Medium ### Vulnerable Code Local dependencies are installed automatically without pinned versions or hashes: ```python if not os.path.exists(VENV_PYTHON): import subprocess print("Bootstrapping .colab-venv...", file=sys.stderr) subprocess.check_call(["uv", "venv", VENV_DIR, "--python", "3.12"], stderr=subprocess.DEVNULL) subprocess.check_call([ "uv", "pip", "install", "--python", VENV_PYTHON, "google-auth-oauthlib", "google-auth", "jupyter-kernel-client", "requests", "google-api-python-client", ]) print("Venv ready.", file=sys.stderr) ``` F5-TTS is also installed dynamically inside the remote runtime: ```python try: import f5_tts print("F5-TTS already installed") except ImportError: print("Installing F5-TTS...") subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "f5-tts[eval]"]) print("F5-TTS installed") ``` ### Technical Analysis The package specifications contain no exact versions, integrity hashes, lockfile, or explicit trusted package index. Therefore, each new environment may install a different dependency graph. Package installation and subsequent imports execute code supplied by external package repositories and package maintainers. This behavior is especially sensitive because the local environment handles OAuth credentials, while the remote F5-TTS environment handles reference voice audio and generated content. A compromised upstream release, compromised maintainer account, malicious transitive dependency, or unexpected future package behavior could access these assets. The package names do not appear to be obvious typosquatting attempts, and no confirmed malicious dependency was identified. The finding concerns the unsafe ...[truncated 1340 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Commit a reviewed dependency lockfile containing exact versions and resolved transitive dependencies. 2. Require cryptographic hashes for downloaded distributions where the package tooling supports them. 3. Configure an explicit trusted package index and disable unintended extra indexes. 4. Build and verify the environment before processing credentials or sensitive user data. 5. Avoid automatic dependency installation during ordinary Skill execution. 6. Use a prebuilt, versioned, integrity-verified runtime image for F5-TTS where practical. 7. Run dependency installation and model execution in isolated environments with no access to local OAuth files. 8. Regularly scan and update locked dependencies through a controlled review process. 9. Record the exact dependency versions used for each execution to support reproducibility and incident investigation. ]]>
Vulnerability Patterns
  • 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
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description emphasizes running code on Colab GPU environments and using Drive as persistent storage in support of that compute workflow. However, this code chunk only implements Google Drive file operations and emits helper snippets for mounting/copying files within Colab. There is no logic to start notebooks, connect to Colab runtimes, select GPU types, execute training/inference jobs, or otherwise provide remote compute. While Drive persistence is mentioned in the description, here it is the entire implemented functionality, making the actual primary purpose materially narrower and different from the declared one.

Tp4

High
Category
MCP Tool Poisoning
Confidence
82% confidence
Finding
The core declared purpose of running code on Google Colab, including optional GPU selection and runtime management, is accurately represented by the code. The script clearly assigns Colab VMs, connects to the kernel, executes code, lists/stops runtimes, and resumes sessions. However, the description also claims management of persistent storage via Google Drive, which is not present in this code chunk—there is no Drive mounting, file transfer, or Drive API usage for storage operations. Additionally, the code exposes extra capabilities not mentioned in the description, notably fetching account/compute information from Colab APIs and saving runtime state locally for later resume. These are not merely incidental implementation details because they are explicit user-facing commands/features. Therefore this is a partial but material description/behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description focuses on running workloads on Google Colab GPU instances and using Drive for persistent storage in support of those workloads. This code chunk does not launch Colab, run remote code, manage GPU sessions, or perform ML/TTS tasks. Its primary purpose is credential management: checking an existing token, initiating a browser-based OAuth flow, requesting Drive scope, and saving updated credentials locally. While Drive access is related to the broader Colab/Drive ecosystem, this specific behavior is a distinct auth utility and is not accurately represented by the declared purpose.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
VENV_PYTHON = os.path.join(os.path.dirname(__file__), ".colab-venv", "bin", "python")
if os.path.exists(VENV_PYTHON) and sys.executable != VENV_PYTHON:
    os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv)

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
VENV_PYTHON = os.path.join(os.path.dirname(__file__), ".colab-venv", "bin", "python")
if os.path.exists(VENV_PYTHON) and sys.executable != VENV_PYTHON:
    os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv)

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
VENV_PYTHON = os.path.join(os.path.dirname(__file__), ".colab-venv", "bin", "python")
if os.path.exists(VENV_PYTHON) and sys.executable != VENV_PYTHON:
    os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv)

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
VENV_PYTHON = os.path.join(os.path.dirname(__file__), ".colab-venv", "bin", "python")
if os.path.exists(VENV_PYTHON) and sys.executable != VENV_PYTHON:
    os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv)

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares powerful capabilities—shell execution, file writes, network access, OAuth flows, and remote code execution—but does not declare any explicit tool scope or permission boundaries. In a skill that can create local auth tokens and send code/data to remote Colab runtimes, missing scope declarations increases the chance of overbroad access and unsafe invocation.

Session Persistence

Medium
Category
Rogue Agent
Content
## Setup

1. **Authenticate with Colab** (one-time): Run the `colab-mcp` OAuth flow to create `~/.colab-mcp-auth-token.json`. See https://github.com/googlecolab/colab-mcp
2. **Add Drive scope** (optional, for persistence): `scripts/reauth_with_drive.py`
3. **Enable Drive API** (if using Drive): https://console.developers.google.com/apis/api/drive.googleapis.com — enable for your GCP project
4. **Python deps**: On first run, `colab_run.py` auto-creates a `.colab-venv/` venv via `uv` and installs deps. Requires `uv` (install: `pip install uv`). Deps: `google-auth-oauthlib`, `google-auth`, `jupyter-kernel-client`, `requests`, `google-api-python-client`
Confidence
83% confidence
Finding
Persisting authentication tokens in the user's home directory creates a standing credential that may be reused by other local processes, exposed via backups, or accessed if file permissions are weak. In a skill that also supports Drive scope expansion and remote execution workflows, long-lived local token storage increases the blast radius of compromise.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The skill instructs users to inject a local OAuth token into code sent to a remote Colab runtime, where it is decoded and written to /tmp/token.json. This exposes credentials across a trust boundary and could allow token theft, misuse of Google Drive access, or persistence of sensitive credentials in logs, notebooks, runtime state, or compromised remote environments.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This markdown example describes injecting reference audio for a voice-cloning workflow but provides no warning that the audio may contain personal biometric data or that users should have consent to use it. For markdown files, SQP-2 applies when descriptions omit warnings about behaviors that could affect user privacy.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This example encourages token injection into a script and execution against Google Drive without warning about credential scope, storage, or the fact that the run can modify cloud files. In a remote-code-execution context like Colab, exposing an OAuth token to templated code materially increases the risk of credential misuse, accidental disclosure, or unintended Drive operations if the script is altered or misused.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The checkpointing template writes injected Drive credentials to disk, enumerates files in Drive, deletes prior checkpoints, and replaces them, yet omits warning that it performs destructive cloud file operations. In the Colab skill context, where users are encouraged to run remote code with persistent storage access, this is more dangerous because a modified or misunderstood template could overwrite or remove Drive content beyond the user's expectations.

Session Persistence

Medium
Category
Rogue Agent
Content
# List files in a Drive folder
    python3 colab_drive.py list --folder colab-workspace

Inside Colab scripts, use these helpers to read/write Drive:
    # At the START of your Colab script:
    from google.colab import auth
    auth.authenticate_user()
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
This skill silently creates a local virtual environment and installs packages on the host machine, which exceeds the stated remote-execution purpose. In a skill context, that is more dangerous because users may reasonably expect actions to occur in Colab, not to mutate the local system or introduce local supply-chain exposure.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not os.path.exists(VENV_PYTHON):
    import subprocess
    print("Bootstrapping .colab-venv...", file=sys.stderr)
    subprocess.check_call(["uv", "venv", VENV_DIR, "--python", "3.12"], stderr=subprocess.DEVNULL)
    subprocess.check_call([
        "uv", "pip", "install",
        "--python", VENV_PYTHON,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
import subprocess
    print("Bootstrapping .colab-venv...", file=sys.stderr)
    subprocess.check_call(["uv", "venv", VENV_DIR, "--python", "3.12"], stderr=subprocess.DEVNULL)
    subprocess.check_call([
        "uv", "pip", "install",
        "--python", VENV_PYTHON,
        "google-auth-oauthlib", "google-auth", "jupyter-kernel-client", "requests",
Confidence
91% confidence
Finding
The script automatically installs Python packages onto the host at runtime, despite the skill's purpose being remote Colab execution. This expands trust to local package resolution and installation, creating unnecessary supply-chain and host-modification risk if package sources are compromised or if the user did not expect any local system changes.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding
The re-authentication guidance tells users to run an unpinned remote repository via uvx git+https://github.com/googlecolab/colab-mcp. Even though this string is not executed by this script, it encourages a supply-chain-risky recovery path where future repository changes could alter what code users run locally.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The skill expands beyond stated Colab/F5-TTS execution into ElevenLabs voice retrieval and third-party TTS generation, which changes the data-flow and trust boundary. That broadening can cause users to disclose API keys, voice assets, and content to an external provider they may not expect from the manifest description.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
Voice samples and reference text are written to a persistent directory under the user's home directory without explicit disclosure or consent. Because voice recordings are sensitive biometric data, silent persistence increases privacy risk, especially on shared systems or when users assume temporary processing.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
This code contacts a third-party voice service and stores/downloads voice samples even though the skill is described primarily as a Colab GPU execution helper. The mismatch increases the risk of unintended transmission of sensitive biometric voice data and credentials outside the expected Colab workflow.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The script accepts an ElevenLabs API key and immediately uses it for outbound requests without clearly warning the user that the credential and associated requests are being sent to an external service. In an agent-skill context, undisclosed credential handling can lead to accidental secret exposure and misuse of paid API access.

External Transmission

Medium
Category
Data Exfiltration
Content
os.makedirs(VOICE_DIR, exist_ok=True)
    
    headers = {"xi-api-key": api_key}
    resp = requests.get(f"https://api.elevenlabs.io/v1/voices/{voice_id}", headers=headers)
    resp.raise_for_status()
    voice = resp.json()
Confidence
80% confidence
Finding
The GET request to ElevenLabs transmits the provided API key to an external service and reveals that the user is querying a voice resource there. While expected for functionality, it is still a real trust-boundary crossing that should be disclosed in a security review.

External Transmission

Medium
Category
Data Exfiltration
Content
if not samples:
        print("No samples found. Generating a reference sample via TTS...")
        # Generate a reference clip using ElevenLabs itself
        gen_resp = requests.post(
            f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
            headers={**headers, "Content-Type": "application/json"},
            json={
Confidence
87% confidence
Finding
This request sends text to ElevenLabs for third-party TTS generation, creating an external data transfer that may not be obvious from the skill description. If the text contains sensitive or proprietary content, it is exposed to an external provider and subject to that provider's handling policies.

External Transmission

Medium
Category
Data Exfiltration
Content
print("No samples found. Generating a reference sample via TTS...")
        # Generate a reference clip using ElevenLabs itself
        gen_resp = requests.post(
            f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
            headers={**headers, "Content-Type": "application/json"},
            json={
                "text": "Hello, I'm Ren. I'm a research assistant who helps with mathematics, coding, and all sorts of intellectual adventures. Nice to meet you.",
Confidence
88% confidence
Finding
This POST sends content to ElevenLabs to synthesize a new reference clip when samples are absent, introducing unadvertised third-party processing. It expands the data shared externally and may generate/stash a biometric reference without the user's explicit understanding.

Static analysis

No suspicious patterns detected.