Back to skill

Security audit

Baoyu Danger Gemini Web

Security checks for vulnerabilities and agentic risk

Overview

This skill performs Gemini generation, but it also reuses and stores Google browser session cookies in ways that need careful review before installation.

Install only if you are comfortable with a reverse-engineered Gemini Web client using Google browser session cookies. Prefer a dedicated Chrome profile via `--profile-dir` or `GEMINI_WEB_CHROME_PROFILE_DIR`, avoid reusing your normal browser session, protect or delete the cookie cache, and avoid the unpinned `npx -y bun` fallback in sensitive environments.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/gemini-webapi/utils/load-browser-cookies.ts:101
Finding
Existing Chrome Debugging Sessions Are Reused to Extract Google Authentication Cookies<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gemini-webapi/utils/load-browser-cookies.ts:101-163` and `scripts/gemini-webapi/utils/load-browser-cookies.ts:263-271` **Vulnerability Type**: Existing browser-session credential extraction beyond least privilege **Risk Level**: High ### Vulnerable Code ```ts async function fetch_cookies_from_existing_chrome( timeoutMs: number, verbose: boolean, ): Promise<CookieMap | null> { const discovered = await discoverRunningChromeDebugPort(); if (discovered === null) return null; if (verbose) logger.info(`Found reusable Chrome debugging session on port ${discovered.port}. Connecting via WebSocket...`); let cdp: CdpConnection | null = null; let targetId: string | null = null; let createdTarget = false; try { const connectStart = Date.now(); const connectTimeout = 30_000; let lastConnErr: unknown = null; while (Date.now() - connectStart < connectTimeout) { try { cdp = await CdpConnection.connect(discovered.wsUrl, 5_000); break; } catch (e) { lastConnErr = e; if (verbose) logger.debug(`WebSocket connect attempt failed: ${e instanceof Error ? e.message : String(e)}, retrying...`); await sleep(1000); } } if (!cdp) { if (verbose) logger.debug(`Could not connect to Chrome after ${connectTimeout / 1000}s: ${lastConnErr instanceof Error ? lastConnErr.message : String(lastConnErr)}`); return null; } const page = await openPageSession({ cdp, reusing: false, url: GEMINI_APP_URL, matchTarget: (target) => target.type === 'page' && target.url.includes('gemini.google.com'), enableNetwork: true, activateTarget: false, }); const { sessionId } = page; targetId = page.targetId; createdTarget = page.createdTarget; if (verbose) logger.debug(createdTarget ? 'No Gemini tab found, creating new tab...' : 'Found existing Gemini tab, attaching...'); con ...[truncated 3448 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a dedicated Chrome profile by default and remove automatic discovery of ordinary browser profiles. 2. Require explicit, immediate user authorization before attaching to an existing browser debugging session. 3. Make existing-session reuse an opt-in command-line option rather than the default fallback. 4. Allowlist only the cookie names strictly required for Gemini authentication, such as the specifically documented session cookies. 5. Do not retain unrelated Google cookies returned by `Network.getCookies`. 6. Clearly display the browser profile and domains that will be accessed before connecting. 7. Fail closed if the discovered WebSocket URL is not loopback-bound or does not correspond to the expected Chrome instance. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gemini-webapi/utils/cookie-file.ts:64
Finding
Google Session Cookies Are Persisted in Plaintext Without Explicit Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gemini-webapi/utils/cookie-file.ts:64-78` **Vulnerability Type**: Plaintext storage of sensitive authentication credentials **Risk Level**: High ### Vulnerable Code ```ts export async function write_cookie_file( cookies: CookieMap, p: string = resolveGeminiWebCookiePath(), source?: string, ): Promise<void> { const dir = path.dirname(p); await mkdir(dir, { recursive: true }); const payload: CookieFileData = { version: 1, updatedAt: new Date().toISOString(), cookieMap: cookies, source, }; await writeFile(p, JSON.stringify(payload, null, 2), 'utf8'); } ``` ### Technical Analysis The complete cookie map is serialized to a plaintext JSON file. The implementation does not use an operating-system credential store, encryption, an explicit `0600` creation mode, or a post-write permission check. It also stores the whole collected map rather than only the minimum cookie fields required for Gemini. Default permissions may be affected by the process umask, but relying on ambient umask behavior is not a robust protection for high-value authentication material. A custom cookie path can also place the file in a shared, synchronized, or otherwise unsuitable directory. ### Attack Path 1. The Skill extracts or receives valid Google authentication cookies. 2. Initialization, refresh, or CDP login calls `write_cookie_file`. 3. The full cookie map is written to `cookies.json` as readable JSON. 4. Another local process, a different local user where permissions allow it, backup software, synchronization tooling, or malware reads the file. 5. The recovered cookies are replayed against relevant Google endpoints before expiration or revocation. ### Impact Assessment Exposure can grant the attacker the authenticated privileges represented by the stored session cookies. At minimum, this may permit unauthorized Gemini requests under the victim's account. Depending on Google's cookie scope ...[truncated 172 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store authentication secrets in the platform credential service, such as Keychain, Credential Manager, or Secret Service. 2. If file storage is unavoidable, create the directory with mode `0700` and the file atomically with mode `0600`. 3. Verify and repair permissions on existing files before reading or updating them. 4. Persist only explicitly allowlisted cookies required for Gemini instead of the complete browser cookie map. 5. Reject custom cookie paths located in insecure or shared directories, or warn and require explicit confirmation. 6. Implement secure deletion or prompt revocation when the user logs out or withdraws consent. 7. Document the sensitivity and lifetime of the stored credentials. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:21
Finding
Unpinned Bun Runtime Is Automatically Downloaded and Executed Through npx<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:21-24` and `scripts/main.ts:60-74` **Vulnerability Type**: Unpinned runtime dependency and mutable supply-chain execution **Risk Level**: Medium ### Vulnerable Code From `SKILL.md`: ```md **Agent Execution Instructions**: 1. Determine this SKILL.md file's directory path as `{baseDir}` 2. Script path = `{baseDir}/scripts/<script-name>.ts` 3. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun 4. Replace all `{baseDir}` and `${BUN_X}` in this document with actual values ``` From `scripts/main.ts`: ```ts function formatScriptCommand(fallback: string): string { const raw = process.argv[1]; const displayPath = raw ? (() => { const relative = path.relative(process.cwd(), raw); return relative && !relative.startsWith("..") ? relative : raw; })() : fallback; const quotedPath = displayPath.includes(" ") ? `"${displayPath.replace(/"/g, '\\"')}"` : displayPath; return `npx -y bun ${quotedPath}`; } ``` ### Technical Analysis When Bun is not installed, the Skill instructs the Agent to use `npx -y bun`. This downloads and executes a mutable registry package without specifying an audited version or integrity value. The `-y` option suppresses interactive confirmation. The package currently being benign does not remove the supply-chain risk: future package replacement, account compromise, registry compromise, or an incompatible release could change the code executed during Skill startup. Because the downloaded runtime executes locally, it receives the same filesystem, environment, browser, and network privileges as the Skill. ### Attack Path 1. Bun is absent but npm/npx is available. 2. The Agent follows `SKILL.md` and invokes `npx -y bun`. 3. npx resolves the current registry version of the package rather than a reviewed, immutable artifact. 4. npm downloads and executes package-controlled code ...[truncated 553 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require a preinstalled, trusted Bun binary for normal execution. 2. If automatic acquisition is necessary, pin a reviewed Bun package version rather than resolving the latest version. 3. Validate downloaded artifacts with a trusted integrity hash or signature. 4. Remove `-y` so installation cannot occur silently. 5. Provide installation instructions separately from routine Skill execution. 6. Record and periodically review the exact runtime and dependency versions supported by the Skill. ]]>

other

Warning
Location
scripts/main.ts:395
Finding
Documented Consent Requirement Is Not Enforced by the Executable CLI<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:32-48` and `scripts/main.ts:395-445` **Vulnerability Type**: Consent-control bypass for reverse-engineered API use and browser credential access **Risk Level**: Medium ### Vulnerable Code The documentation declares consent mandatory: ```md ## Consent Check (REQUIRED) Before first use, verify user consent for reverse-engineered API usage. **Consent file locations**: - macOS: `~/Library/Application Support/baoyu-skills/gemini-web/consent.json` - Linux: `~/.local/share/baoyu-skills/gemini-web/consent.json` - Windows: `%APPDATA%\baoyu-skills\gemini-web\consent.json` **Flow**: 1. Check if consent file exists with `accepted: true` and `disclaimerVersion: "1.0"` 2. If valid consent exists → print warning with `acceptedAt` date, proceed 3. If no consent → show disclaimer, ask user via `AskUserQuestion`: - "Yes, I accept" → create consent file with ISO timestamp, proceed - "No, I decline" → output decline message, stop 4. Consent file format: `{"version":1,"accepted":true,"acceptedAt":"<ISO>","disclaimerVersion":"1.0"}` ``` The executable entry point proceeds without checking that record: ```ts async function main(): Promise<void> { const args = parseArgs(process.argv.slice(2)); if (args.cookiePath) process.env.GEMINI_WEB_COOKIE_PATH = args.cookiePath; if (args.profileDir) process.env.GEMINI_WEB_CHROME_PROFILE_DIR = args.profileDir; const cookiePath = resolveGeminiWebCookiePath(); const profileDir = resolveGeminiWebChromeProfileDir(); if (args.help) { printUsage(cookiePath, profileDir); return; } if (args.listSessions) { const ss = await listSessions(); for (const s of ss) { const n = s.messages.length; const last = s.messages.slice(-1)[0]; const lastLine = last?.content ? String(last.content).split('\n')[0] : ''; console.log(`${s.id}\t${s.updatedAt}\t${n}\t${lastLine}`); } return; } if (args.login) { process.env.GEMIN ...[truncated 2054 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement the consent check in executable code before client initialization, login, cookie access, uploads, or external requests. 2. Validate the exact schema, including `accepted: true` and the current disclaimer version. 3. Fail closed when the record is absent, malformed, outdated, or explicitly declined. 4. Require interactive confirmation where an interactive environment is available. 5. For noninteractive use, require a deliberate administrative provisioning mechanism rather than silently proceeding. 6. Display the accepted timestamp and warning described by the documentation on every relevant invocation. 7. Place the consent check in a shared initialization function so alternate entry points cannot bypass it. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Launching Chrome, inspecting user-data directories, scanning processes for debugging flags, and attaching to local DevTools Protocol sessions can grant effective control over an already authenticated browser. In an agent setting this is especially dangerous because it can expose cookies, page content, and account actions far outside the narrow scope of text/image generation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Launching Chrome, inspecting user-data directories, scanning processes for debugging flags, and attaching to local DevTools Protocol sessions can grant effective control over an already authenticated browser. In an agent setting this is especially dangerous because it can expose cookies, page content, and account actions far outside the narrow scope of text/image generation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Launching Chrome, inspecting user-data directories, scanning processes for debugging flags, and attaching to local DevTools Protocol sessions can grant effective control over an already authenticated browser. In an agent setting this is especially dangerous because it can expose cookies, page content, and account actions far outside the narrow scope of text/image generation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Launching Chrome, inspecting user-data directories, scanning processes for debugging flags, and attaching to local DevTools Protocol sessions can grant effective control over an already authenticated browser. In an agent setting this is especially dangerous because it can expose cookies, page content, and account actions far outside the narrow scope of text/image generation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Launching Chrome, inspecting user-data directories, scanning processes for debugging flags, and attaching to local DevTools Protocol sessions can grant effective control over an already authenticated browser. In an agent setting this is especially dangerous because it can expose cookies, page content, and account actions far outside the narrow scope of text/image generation.

Ae1

High
Category
analysis-evasion
Content
| `scripts/main.ts` | CLI entry point for text/image generation |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

External Model or Provider Selection

High
Category
Excessive Agency
Content
```bash
# Text generation
${BUN_X} {baseDir}/scripts/main.ts "Your prompt"
${BUN_X} {baseDir}/scripts/main.ts --prompt "Your prompt" --model gemini-3-flash

# Image generation
${BUN_X} {baseDir}/scripts/main.ts --prompt "A cute cat" --image cat.png
Confidence
90% confidence
Finding
Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Credential Access

High
Category
Privilege Escalation
Content
if (this.auto_close) await this.reset_close_task();

      if (!this.access_token) throw new APIError('Missing access token.');

      const f = files?.length ? files : null;
      const uploaded =
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
if (this.auto_close) await this.reset_close_task();

      if (!this.access_token) throw new APIError('Missing access token.');

      const f = files?.length ? files : null;
      const uploaded =
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
Login || (!cachedFile && !base_cookies['__Secure-1PSID'] && !base_cookies['__Secure-1PSIDTS']);

  if (shouldUseChromeFirst) {
    try {
      const browser = await load_browser_cookies('google.com', verbose);
      for (const cookies of Object.values(browser)) {
        candidates.push(merge_cookie_maps(extra, cookies));
      }
    } catch (e) {
      if (verbose) logger.warning(`Failed to load cookies via Chrome CDP: ${e instanceof Error ? e.message : String(e)}`);
    }
  }

  if (base_cookies['__Secure-1PSID'] && base_cookies['__Secure-1PSIDTS']) {
    candidates.push(merge_cookie_maps(extra, base_cookies));
  } else if (verbose) {
    logger.debug('Skipping loading base cookies. Either __Secure-1PSID or __Secure-1PSIDTS is not provided.');
  }

  if (cachedFile) {
    candidates.push(merge_cookie_maps(extra, cachedFile));
  }

  if (base_cookies['__Secure-1PSID'] && !base_cookies['__Secure-1PSIDTS']) {
    const sid = base_cookies['__Secure-1PSID'];
    const sidts = read_cached_
Confidence
87% confidence
Finding
The malware-style match is justified here because the file implements behavior commonly seen in info-stealers: harvesting authenticated browser cookies, trying multiple cached candidates, and replaying them to a remote service. While the apparent goal is service access rather than generic theft, the mechanism is still dangerous because it enables covert reuse of credentials from local browser state.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
0,
    });

    if (!res.ok) {
      if (verbose) logger.debug(`Gemini init check failed: ${res.status} ${res.statusText}`);
      return false;
    }

    const text = await res.text();
    return /\"SNlM0e\":\"(.*?)\"/.test(text);
  } catch (e) {
    if (verbose) logger.debug(`Gemini init check error: ${e instanceof Error ? e.message : String(e)}`);
    return false;
  }
}

async function fetch_cookies_from_existing_chrome(
  timeoutMs: number,
  verbose: boolean,
): Promise<CookieMap | null> {
  const discovered = await discoverRunningChromeDebugPort();
  if (discovered === null) return null;

  if (verbose) logger.info(`Found reusable Chrome debugging session on port ${discovered.port}. Connecting via WebSocket...`);

  let cdp: CdpConnection | null = null;
  let targetId: string | null = null;
  let createdTarget = false;
  try {
    const connectStart = Date.now();
    const connectTimeout = 30_000;
    let lastConnErr: unknown = null;
    while (Date.now() - connectStart < conne
Confidence
97% confidence
Finding
The function discovers an existing Chrome remote-debugging session, attaches via CDP, enumerates cookies for Google domains, validates that they are sufficient for a Gemini session, and then later writes them to a cookie file. This is a classic browser-session theft pattern: it accesses authentication cookies from another browser context without a normal authentication flow, enabling impersonation of the logged-in user.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill declares no explicit tool scope even though it clearly needs environment access, filesystem access, browser/profile access, and network connectivity. In an agent ecosystem this weakens policy enforcement and can cause the skill to be invoked with broader capabilities than users or orchestrators expect.

Vague Triggers

Medium
Confidence
93% confidence
Finding
Broad activation wording like 'use when other skills need image generation backend' or generic Gemini/image requests can cause the skill to be selected in many contexts without the user understanding that it uses a reverse-engineered API, browser automation, cookies, and local profile access. Over-broad routing increases the chance of unsafe invocation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
Using `npx -y bun` without pinning a specific version makes execution depend on whatever package/version is resolved at runtime. That creates supply-chain risk and undermines reproducibility, allowing a compromised or incompatible upstream package to execute code in the agent context.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**Flow**:
1. Check if consent file exists with `accepted: true` and `disclaimerVersion: "1.0"`
2. If valid consent exists → print warning with `acceptedAt` date, proceed
3. If no consent → show disclaimer, ask user via `AskUserQuestion`:
   - "Yes, I accept" → create consent file with ISO timestamp, proceed
   - "No, I decline" → output decline message, stop
4. Consent file format: `{"version":1,"accepted":true,"acceptedAt":"<ISO>","disclaimerVersion":"1.0"}`
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The client writes live Gemini authentication cookies to a local file during initialization, creating a persistent credential store unrelated to simple in-memory request handling. If the host, workspace, logs, backups, or shared filesystem are accessible to another process or user, these cookies can be stolen and reused to impersonate the account.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This code persists session cookies to disk with no visible warning or consent in this file, so users or downstream integrators may not realize account credentials are being stored locally. Undisclosed secret persistence raises the chance of accidental exposure through source trees, temporary directories, backups, or multi-user environments.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The background auto-refresh loop extends the lifetime of authenticated session cookies and writes refreshed credentials back to disk, effectively maintaining long-lived access without additional user action. This increases exposure because stolen persisted cookies remain valid longer and the skill behavior exceeds one-shot generation into credential lifecycle management.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Refreshed authentication cookies are silently rewritten to disk in the background, which can surprise users who may believe credentials were only used transiently. Continuous undisclosed secret updates make forensics, revocation, and risk management harder because sensitive state is maintained outside the immediate request flow.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
This mixin exposes functionality to list, create, update, and delete persistent Gemini 'gems', which materially exceeds the skill's declared role as a text/image generation backend. That scope expansion is dangerous because it enables remote modification of long-lived user assets or assistants on gemini.google.com, creating opportunities for unauthorized persistence, prompt tampering, or account-state changes beyond a single generation request.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The create_gem, update_gem, and delete_gem methods perform persistent remote operations against the user's Gemini Web account without any visible justification tied to transient text/image generation. In this skill context, that is more dangerous because a backend expected to generate content can instead implant or alter reusable assistants, changing future model behavior and causing durable account-side effects the user may not anticipate.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The delete_gem method issues a destructive remote deletion immediately after receiving a gem identifier, with no confirmation, soft-delete, or user-facing safety check visible here. In a skill advertised for generation tasks, hidden destructive account operations are especially risky because they can erase user-created assistants or configurations through misuse, confused-deputy behavior, or malicious upstream prompting.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The save method performs an HTTP GET and may attach a Cookie header derived from caller-supplied cookies, which can transmit authenticated session data to the target URL. In this file, there is no confirmation prompt and no user-facing logging or comment/docstring warning that saving an image may send cookies to a remote server.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code persists a cookie map to a filesystem path, which is a safety-relevant file write involving sensitive session data. The function contains no confirmation prompt, logging, comment, or docstring warning that authentication cookies will be stored on disk.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The request sends authentication cookies in the HTTP Cookie header to initialize the remote Gemini web session. Even if sent to the intended endpoint over HTTPS, transmitting session cookies acquired from browser state or local cache without transparent disclosure increases the risk of unauthorized account use and session abuse.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/gemini-webapi/utils/paths.ts:38

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/vendor/baoyu-chrome-cdp/src/index.test.ts:89

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/vendor/baoyu-chrome-cdp/src/index.ts:220

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/vendor/baoyu-chrome-cdp/src/index.ts:97