Back to skill

Security audit

gogcli-mcp-gmail

Security checks for vulnerabilities and agentic risk

Overview

ClawScan rates this skill suspicious with medium confidence, citing a high-impact flaw in Gmail forwarding confirmation and capabilities that extend beyond its declared Gmail scope.

Consider the forwarding-filter confirmation flaw and the extra attachment destinations before installing, especially if the account contains sensitive email. Scanning was partial: 16 of 23 components were fully inspected, and several analyzers had coverage limits, so the remaining evidence is incomplete.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
src/tools/gmail-extra.ts
Finding

Forwarding-filter confirmation is not bound to the approved operation

Content
View full analysis

Impact

The caller can create a persistent forwarding filter broader than the approved filter, or targeting a different already-verified address, disclosing future matching email without approval of that operation.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (61)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Drive delivery expands a tool advertised as Gmail-only into a cross-service write capability. For sensitive attachments, this can create copies under different sharing and retention policies; however, the supplied source does not establish the claimed folder-selection implementation or an OAuth bypass.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The attachment documentation confirms optional Drive writes and signed-link delivery despite the narrower description. These modes change where sensitive email data is stored and who can retrieve it, making accurate capability disclosure important; arbitrary destination selection and improper blob access controls are not established here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The documented Drive and signed-URL delivery modes extend attachment handling beyond Gmail: they create another copy or a temporary bearer-accessible download. This supports a scope-disclosure concern, not proof that signed URLs are inherently insecure; the calendar-event claim is not substantiated by this source.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The documented drive mode permits a non-Gmail write through an ostensibly Gmail-only attachment tool. This is an explicit scope mismatch with confidentiality implications for mailbox attachments, though it is openly documented rather than evidence of malicious exfiltration.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
78% confidence
Finding

The Gmail registrations and authentication bootstrap match the declared purpose. However, registerUploadTools is also explicitly registered, expanding the exposed tool surface beyond the stated restriction. Its implementation is not supplied, so upload destinations and side effects cannot be determined. If these tools exclusively support Gmail attachments, they would instead qualify as supporting implementation details.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [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 · dist/index.js (reported line 51)May include surrounding context.

js
../node_modules/@chrischall/mcp-utils/dist/caller/index.js
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
var storage2 = new AsyncLocalStorage2();
function withCallerCapabilities(capabilities, fn) {
  return capabilities ? storage2.run(capabilities, fn) : fn();
}
function currentCallerCapabilities() {
  return storage2.getStore();
}
var ENVELOPE_CAPABILITIES_KEY = "io.modelcontextprotocol/clientCapabilities";
var ELICITATION_MODES = ["form", "url"];
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function callerCapabilities(ctx) {
  const envelope = isRecord(ctx) && isRecord(ctx.mcpReq) ? ctx.mcpReq.envelope : void 0;
  if (isRecord(envelope)) {
    const declared = envelope[ENVELOPE_CAPABILITIES_KEY];
    if (isRecord(declared))
      return declared;
  }
  return currentCallerCapabilities();
}
function callerAcceptsFormElicitation(ctx) {
  const capabilities = callerCapabilities(ctx);
  if (!capa

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · dist/index.js (reported line 27159)May include surrounding context.

js
function validateAsync3() {
      const ruleErrs = gen.let("ruleErrs", null);
      gen.try(() => assignValid((0, codegen_1._)`await `), (e) => gen.assign(valid, false).if((0, codegen_1._)`${e} instanceof ${it.ValidationError}`, () => gen.assign(ruleErrs, (0, codegen_1._)`${e}.errors`), () => gen.throw(e)));
      return ruleErrs;
    }
    function validateSync() {
      const validateErrs = (0, codegen_1._)`${validateRef}.errors`;

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · dist/index.js (reported line 33986)May include surrounding context.

js
if (typeof promptName !== "string") return;
        const prompt = this._registeredPrompts[promptName];
        if (prompt === void 0 || !prompt.enabled) return;
        return prompt.scopeChallenge?.(context);
      }
      default:
        return;

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · dist/index.js (reported line 34188)May include surrounding context.

js
const prompt = this._registeredPrompts[request.params.name];
      if (!prompt) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Prompt ${request.params.name} not found`);
      if (!prompt.enabled) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Prompt ${request.params.name} disabled`);
      return prompt.handler(request.params.arguments, ctx);
    });
    this._promptHandlersInitialized = true;
  }

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · dist/index.js (reported line 35317)May include surrounding context.

js
return walk(value, keep, drop);
}
function normalizeRules(rules) {
  return rules.map((rule) => typeof rule === "string" ? rule.toLowerCase() : new RegExp(rule.source, rule.flags));
}
function matchesRule(key, rules) {
  const lower = key.toLowerCase();

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/index.js (reported line 36876)May include surrounding context.

js
var TOKEN_LEFT_BOUNDARY = "(?<![A-Za-z0-9+/])";
var GOOGLE_TOKEN_PATTERNS = [
  new RegExp(`${TOKEN_LEFT_BOUNDARY}ya29\\.[A-Za-z0-9._\\-]+`, "g"),
  // OAuth2 access tokens
  new RegExp(`${TOKEN_LEFT_BOUNDARY}1//[A-Za-z0-9._\\-]+`, "g")
  // OAuth2 refresh tokens
];

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/index.js (reported line 37646)May include surrounding context.

js
}
  });
  server.registerTool("gog_auth_status", {
    description: "Show gogcli auth CONFIGURATION: keyring backend, credential files, and auth setup. Despite the name this is not a health check \u2014 it reads local setup and does not contact Google, so it says nothing about whether an account can still authenticate. Use gog_auth_health for that.",
    annotations: { readOnlyHint: true, openWorldHint: false },
    inputSchema: external_exports.object({})
  }, async () => {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/index.js (reported line 37657)May include surrounding context.

js
}
  });
  server.registerTool("gog_auth_health", {
    description: `Check the LIVE health of each stored Google account. Unlike gog_auth_status (which only reports keyring/config setup), this performs a real token refresh against Google, so it detects expired or revoked (invalid_grant) refresh tokens \u2014 the account-wide sign-out that blocks every service. Reports per account: whether the token is currently valid, the mapped cause when it is not, how long ago it was authorized, and a warning as it approaches the 7-day refresh-token limit that applies to OAuth apps whose consent screen is still in "Testing" mode. Run it proactively to re-authorize on your own schedule instead of mid-task. On a hosted deployment this is the ONLY check that measures Google: a connector showing "connected" or "refreshed" has verified the client's connection to the MCP host, and nothing else \u2014 the Google credential lives in gog's keyring on that host and can be dead while the connection looks p

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/index.js (reported line 37657)May include surrounding context.

js
tus (which only reports keyring/config setup), this performs a real token refresh against Google, so it detects expired or revoked (invalid_grant) refresh tokens \u2014 the account-wide sign-out that blocks every service. Reports per account: whether the token is currently valid, the mapped cause when it is not, how long ago it was authorized, and a warning as it approaches the 7-day refresh-token limit that applies to OAuth apps whose consent screen is still in "Testing" mode. Run it proactively to re-authorize on your own schedule instead of mid-task. On a hosted deployment this is the ONLY check that measures Google: a connector showing "connected" or "refreshed" has verified the client's connection to the MCP host, and nothing else \u2014 the Google credential lives in gog's keyring on that host and can be dead while the connection looks perfectly healthy.`,
    annotations: { readOnlyHint: true, openWorldHint: true },
    inputSchema: external_exports.object({})
  }, async () => {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/tools/gmail-extra.ts (reported line 337)May include surrounding context.

ts
//
// The id is the caller's string and gog MkdirAll's whatever it is told, so a raw
// `../../x` walked the write out of the attachment root — on a hosted deployment
// potentially into the data directory that holds gog's keyring and refresh token. deliver="url" was
// held to one segment from the start because its path and its object key have to
// be the same string, so the gap was visible there as a refused upload and
// invisible in the four modes that only write; the rule is the SAME rule

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 20)May include surrounding context.

yaml
required: false
    help: >-
      Google OAuth client id. Read by the Node wrapper at startup
      (bootstrap-auth.ts), which imports it into gog's keyring via a temp file
      together with GOG_CLIENT_SECRET, GOG_REFRESH_TOKEN and GOG_ACCOUNT — set
      all four or none. Not a secret, so unlike GOG_CLIENT_SECRET and
      GOG_REFRESH_TOKEN it is not stripped from the spawned `gog`'s

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/index.ts (reported line 7)May include surrounding context.

ts
import { registerExtraGmailTools } from './tools/gmail-extra.js';


// Seed gog's keyring from GOG_CLIENT_ID/SECRET/REFRESH_TOKEN/ACCOUNT when the host injects them.
await bootstrapGogAuth();

await runMcp({

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 24)May include surrounding context.

yaml
together with GOG_CLIENT_SECRET, GOG_REFRESH_TOKEN and GOG_ACCOUNT — set
      all four or none. Not a secret, so unlike GOG_CLIENT_SECRET and
      GOG_REFRESH_TOKEN it is not stripped from the spawned `gog`'s
      environment; gog authenticates from its keyring under $HOME (see
      state.dataDir).
  - name: GOG_CLIENT_SECRET
    secret: true

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 30)May include surrounding context.

yaml
secret: true
    required: false
    help: >-
      Google OAuth client secret. Imported into gog's keyring at startup with
      GOG_CLIENT_ID; stripped from the spawned CLI's environment by runner.ts's
      *_SECRET rule.
  - name: GOG_REFRESH_TOKEN

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 59)May include surrounding context.

yaml
required: false
    help: >-
      gog's credential store. Set to "file" on a headless host — there is no OS
      keychain — so the keyring lives on the persistent data dir.
  - name: GOG_KEYRING_PASSWORD
    secret: true
    required: false

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 38)May include surrounding context.

yaml
required: false
    help: >-
      Google OAuth refresh token (`gog auth tokens export` prints one). Imported
      into gog's keyring at startup with GOG_CLIENT_ID; stripped from the
      spawned CLI's environment by runner.ts's *_TOKEN rule. Changing it
      re-imports on the next start; an in-connector re-auth
      (gog_auth_add_url/complete) stays in effect until it changes.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 105)May include surrounding context.

yaml
state:
  dataDir: true
  reason: >-
    `gog` keeps its authorised-account state and file keyring under $HOME, and
    the wrapper keeps its auth-bootstrap marker (~/.gogcli-mcp) there, so a
    restart neither re-imports an unchanged secret nor discards an
    in-connector re-auth. Without a persistent data dir every cold start has

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 55)May include surrounding context.

yaml
The Google account to act as. Required for the startup auth bootstrap
      (the refresh token is imported under this email); otherwise defaults to
      gog's single/most recent account.
  - name: GOG_KEYRING_BACKEND
    required: false
    help: >-
      gog's credential store. Set to "file" on a headless host — there is no OS

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 60)May include surrounding context.

yaml
help: >-
      gog's credential store. Set to "file" on a headless host — there is no OS
      keychain — so the keyring lives on the persistent data dir.
  - name: GOG_KEYRING_PASSWORD
    secret: true
    required: false
    help: >-

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · mint.yaml (reported line 59)May include surrounding context.

yaml
required: false
    help: >-
      gog's credential store. Set to "file" on a headless host — there is no OS
      keychain — so the keyring lives on the persistent data dir.
  - name: GOG_KEYRING_PASSWORD
    secret: true
    required: false