Back to skill

Security audit

Gemini Google Search

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Gemini-backed search helper, but users should treat its API key handling and automatic dependency install with care.

Install only if you are comfortable sending search queries to Gemini/Google and using a Gemini API key from the environment or a narrowly scoped 1Password item. Prefer a local search skill for private queries, and consider pinning or reviewing the google-genai dependency before first use in sensitive environments.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Automatically Installed Dependency Is Not Reproducibly Pinned

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1 and scripts/run_gemini_search.sh:5-7
Vulnerability Type: Insecure third-party dependency management
Risk Level: Medium

Vulnerable code in requirements.txt:

text
google-genai>=1.0.0

Installation code in scripts/run_gemini_search.sh:

bash
if [[ ! -x "$PY" ]]; then
  python3 -m venv "$DIR/.venv"
  "$DIR/.venv/bin/python" -m pip install -r "$DIR/requirements.txt"
fi

Technical Analysis

The wrapper automatically installs google-genai when the local virtual environment does not exist. The requirement specifies only a lower version boundary, so pip may install any current or future release at or above version 1.0.0, together with unpinned transitive dependencies.

No lock file, exact version constraint, or package hash verification is present. Therefore, installing the Skill at different times can cause different third-party code to execute even though the audited project files have not changed.

This does not establish that the current package is malicious. The risk arises because future dependency resolution is not reproducible or cryptographically constrained. A compromised upstream release or transitive dependency could execute installation or runtime code with the invoking user's permissions. At runtime, the dependency is also loaded into the same Python process that receives the Gemini API key.

Attack Path

  1. An attacker compromises an eligible future google-genai release, a transitive dependency, or the relevant package distribution channel.
  2. A user invokes scripts/run_gemini_search.sh where the project-local .venv does not already contain an executable Python interpreter.
  3. The wrapper creates the virtual environment and runs pip automatically.
  4. Pip resolves the unconstrained newer package or compromised transitive dependency.
  5. Attacker-controlled installation or runtime code execu ...[truncated 937 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the open-ended version constraint with a reviewed, exact version.
  2. Generate a lock file that fixes all transitive dependency versions.
  3. Record and enforce package hashes, then install with pip install --require-hashes.
  4. Use an explicitly trusted package index and disable unintended extra indexes to reduce dependency-confusion exposure.
  5. Update dependencies only through a controlled review process that includes vulnerability scanning and regression testing.
  6. Consider separating environment provisioning from normal Skill execution so invocation does not automatically download and execute newly resolved third-party packages.
  7. Rebuild the virtual environment from the reviewed lock file when dependencies are intentionally updated.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The skill explicitly references a workspace-local secrets source that provides a 1Password service-account token for non-interactive access. Even though it says not to print keys, normalizing the presence and use of a broadly accessible token increases the risk of credential discovery, misuse, or unintended propagation to other tools and logs.

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

--op-vault OpenClaw-Core --op-item openclaw-gemini-api

text

Note: `secrets.env` in this workspace provides the OP service-account token for non-interactive 1Password access.

Never print API keys. If using 1Password interactively, follow the 1Password skill's tmux/sign-in guidance.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documentation describes shell execution and environment/credential access, but the skill metadata does not declare any explicit tool scope such as allowed tools or permissions. That omission weakens least-privilege controls and can allow the skill to run with broader capabilities than reviewers or policy engines expect.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gemini_google_search.py (reported line 57)May include surrounding context.

python
if field:
        ref = f"op://{vault}/{item}/{field}"
        try:
            return subprocess.check_output(["op", "read", ref], text=True, stderr=subprocess.PIPE).strip()
        except (subprocess.CalledProcessError, FileNotFoundError) as exc:
            raise RuntimeError(f"Could not read 1Password field {ref}: {exc}") from exc

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gemini_google_search.py (reported line 62)May include surrounding context.

python
raise RuntimeError(f"Could not read 1Password field {ref}: {exc}") from exc

    try:
        raw = subprocess.check_output(
            ["op", "item", "get", item, "--vault", vault, "--format", "json"],
            text=True,
            stderr=subprocess.PIPE,

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower bound only, so installs may resolve to different future versions of google-genai with unreviewed behavior changes or newly introduced security issues. In a skill that performs external web-backed queries and handles API credentials, unpredictable dependency drift increases supply-chain and reliability risk beyond a purely cosmetic packaging issue.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
google-genai>=1.0.0

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/gemini_google_search.py (reported line 22)May include surrounding context.

python
return default
    if isinstance(obj, dict):
        return obj.get(name, default)
    return getattr(obj, name, default)


def _to_plain(obj: Any) -> Any:

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/gemini_google_search.py (reported line 35)May include surrounding context.

python
if isinstance(obj, dict):
        return {str(k): _to_plain(v) for k, v in obj.items()}
    for meth in ("to_json_dict", "model_dump", "dict"):
        fn = getattr(obj, meth, None)
        if callable(fn):
            try:
                return _to_plain(fn())

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code creates a virtual environment and installs dependencies, which writes to disk and executes package installation commands, but the script provides no confirmation prompt, logging, or explanatory comment to inform the user. For a code file, these side effects are safety-relevant and lack visible disclosure in the script itself.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.