Back to skill

Security audit

Gemini Computer Use

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-built for browser automation, but it gives a model broad browser control and sends screenshots and URLs to Gemini without strong local limits.

Install only if you are comfortable with Gemini receiving browser screenshots and current URLs. Run it in an isolated browser/container, avoid authenticated or sensitive sites, block risky actions with --exclude, and prefer adding local allowlists and explicit confirmations before using it for account, payment, admin, or private-network tasks.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/computer_use_agent.py:121
Finding

Model-Controlled Safety Confirmation Fails Open

Content
View full analysis
bool: explanation = safety_decision.get("explanation", "") decision = safety_decision.get("decision", "") print("Safety decision:") if explanation: print(explanation) if decision != "require_confirmation": return True while True: response = input("Proceed with the action? [y/n] ").strip().lower() if response in ("y", "yes"): return True if response in ("n", "no"): return False ``` ```python args = maybe_cast_args(call.args) safety_decision = args.get("safety_decision") if isinstance(args, dict) else None if safety_decision and isinstance(safety_decision, dict): if not prompt_for_safety_confirmation(safety_decision): return {"blocked": "user_denied"}, True ``` ```python results: List[Tuple[str, Dict[str, Any]]] = [] for call in function_calls: print(f"Executing: {call.name}") result, should_stop = execute_function_call( call, page, args.screen_width, args.screen_height ) results.append((call.name, result)) if should_stop: print("Terminating due to safety denial.") browser.close() return 2 ``` ### Technical Analysis The local application asks for confirmation only when the remote model includes a dictionary-valued `safety_decision` field whose `decision` value is exactly `require_confirmation`. If the field is absent, malformed, assigned another type, or contains any other decision value, the action is allowed without an independent local safety assessment. The model is both the source of an action and the source of the metadata that determines ...[truncated 1643 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/computer_use_agent.py:159
Finding

Unrestricted Browser Navigation Can Expose Private Network Resources

Content
View full analysis
List[Any]: screenshot_bytes = page.screenshot(type="png") current_url = page.url responses = [] for name, result in results: payload = {"url": current_url} payload.update(result) responses.append( types.FunctionResponse( name=name, response=payload, parts=[ types.FunctionResponsePart( inline_data=types.FunctionResponseBlob( mime_type="image/png", data=screenshot_bytes, ) ) ], ) ) return responses ``` ```python page = context.new_page() page.goto(args.start_url) ``` ```python response = client.models.generate_content( model=MODEL_NAME, contents=contents, config=config, ) ``` ### Technical Analysis The command-line start URL and model-generated navigation URLs are passed directly to Playwright. The implementation does not validate URL schemes, hostnames, DNS results, destination address ranges, ports, or redirect targets. Consequently, the automated browser may navigate to resources reachable from the host but not intended to be exposed externally, including loopback services, private-network applications, router interfaces, and link-local cloud metadata endpoints. After navigation, the code captures the rendered page and current URL and includes them in a reques ...[truncated 1559 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding

Runtime Dependencies and Browser Components Are Not Version-Pinned

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scripts/computer_use_agent.py (reported line 37)May include surrounding context.

python
_WIDTH = 1440
DEFAULT_SCREEN_HEIGHT = 900

SUPPORTED_ACTIONS = {
    "open_web_browser",
    "wait_5_seconds",
    "go_back",
    "go_forward",
    "search",
    "navigate",
    "click_at",
    "hover_at",
    "type_text_at",
    "key_combination",
    "scroll_document",
    "scroll_at",
    "drag_and_drop",
}


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Run a Gemini Computer Use browser automation loop via Playwright.",
    )
    parser.add_argument("--prompt", required=True, help="User goal to send to the model")
    parser.add_argument(
        "--start-url",
        default=DEFAULT_START_URL,
        help=f"Initial page to load (default: {DEFAULT_START_URL})",
    )
    parser.add_argument("--turn-limit", type=int, default=6, help="Max turns")
    parser.add_argument(
        "--headless",
        action="store_true",
        help="Run browser in headless mode",
    )
    parser.add_argument(
        "--screen-width",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill references environment setup and use of an API key via an env file, but it does not declare an explicit tool scope such as permissions or allowed-tools. In an agent skill that automates browser actions and can influence external systems, missing scope declarations weakens least-privilege controls and can lead to broader-than-expected access to secrets or runtime capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The agent captures browser screenshots and includes the current URL in function responses sent back to the Gemini model without any explicit user-facing notice or consent step at the transmission point. In a browser-control workflow, screenshots and URLs can contain sensitive data such as authenticated pages, personal information, tokens in query strings, or internal application details, so silent transmission increases data-exposure risk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.