Back to skill

Security audit

Book Google Meet

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned for creating Google Meet meetings, but it needs review because it stores Google OAuth tokens unsafely and asks for broader Calendar access than the script appears to need.

Review before installing. Use this only in a trusted local workspace, understand that OPEN meetings allow broad link-based access, and prefer a patched version that avoids pickle, stores tokens with owner-only permissions or a keychain, and removes the unnecessary broad Calendar scope. Revoke the Google OAuth token if the token file may have been exposed.

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)

T09 · Insecure Skill Coding Practices

Error
Location
book_meeting.py:132
Finding
Unsafe Deserialization of a User-Controllable OAuth Token File<![CDATA[ ## Vulnerability Details **File Location**: `book_meeting.py:132-134` **Vulnerability Type**: Unsafe Python pickle deserialization **Risk Level**: High ### Vulnerable Code ```python if os.path.exists(token_path): with open(token_path, 'rb') as token: creds = pickle.load(token) ``` ### Technical Analysis The application restores cached OAuth credentials using `pickle.load()`. Python pickle data is executable serialization: a crafted pickle can invoke arbitrary functions while it is being deserialized. The token path defaults to `meeting_token.pickle` in the current working directory and can also be selected through the `--token-path` argument. The application performs no ownership, permission, file-type, symlink, integrity, or authenticity checks before deserialization. Consequently, any party capable of planting or replacing the selected token file can cause code execution when the Skill starts. The payload executes before Calendar or Meet operations and does not require a valid Google token. ### Attack Path 1. An attacker gains write access to the directory from which the Skill will be launched, or convinces the user to supply an attacker-controlled file through `--token-path`. 2. The attacker creates a malicious pickle object whose reduction routine invokes an arbitrary command or Python callable. 3. The attacker saves it as `meeting_token.pickle` or at the user-selected token path. 4. The user invokes `book_meeting.py`. 5. The `pickle.load(token)` call reconstructs the malicious object and executes its payload. 6. The payload runs with the operating-system privileges of the user invoking the Skill. ### Impact Assessment Successful exploitation provides arbitrary code execution under the invoking user's account. The attacker could read or modify user-accessible files, access environment variables and credentials, steal other local tokens, invoke network services, or alter the meeting-booking operation. The vulnerability does not ...[truncated 117 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace pickle storage with a non-executable format such as JSON. - Serialize only the credential fields required to reconstruct a `google.oauth2.credentials.Credentials` instance. - Store tokens in a dedicated user configuration directory created with mode `0700`. - Create token files atomically with mode `0600`. - Reject symbolic links and non-regular files. - Verify that an existing token file is owned by the current user and is not accessible by group or other users. - If backward compatibility is required, do not automatically deserialize legacy pickle files. Provide an explicit, isolated migration process with strong ownership and permission validation, then delete the legacy file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
book_meeting.py:145
Finding
OAuth Refresh Token Written Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `book_meeting.py:145-146` **Vulnerability Type**: Insecure local storage of sensitive OAuth credentials **Risk Level**: Medium ### Vulnerable Code ```python with open(token_path, 'wb') as token: pickle.dump(creds, token) ``` ### Technical Analysis The cached `Credentials` object may contain an OAuth access token and refresh token. The application writes this object using the default permissions determined by the process umask. Although `SKILL.md` advises users to protect the file, the implementation does not enforce owner-only access. The path is also user-selectable and defaults to the current working directory rather than a private credential directory. On a shared machine, under a permissive umask, or when the selected directory has inappropriate access controls, another local account may be able to read the token. The code also does not validate whether the destination is a symbolic link or an existing file owned by another user. ### Attack Path 1. A user runs the Skill and completes Google OAuth authorization. 2. The application writes the credential object to `meeting_token.pickle` or the path supplied through `--token-path`. 3. The surrounding environment uses permissions that allow another local account or process to read the resulting file. 4. The attacker copies and decodes the cached credentials. 5. If a reusable refresh token is present, the attacker submits it to Google's OAuth token endpoint using the corresponding client configuration. 6. The attacker obtains access tokens carrying the scopes authorized by the user and accesses the permitted Google Calendar or Meet resources. ### Impact Assessment Exposure of a reusable refresh token can permit access to the victim's Google resources within the granted OAuth scopes. In the current implementation, this may include Calendar event management and Google Meet space-setting operations. Access persists until the token is revoked, expires, ...[truncated 116 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store the token under a dedicated per-user configuration directory with mode `0700`. - Create a new token file using an atomic exclusive operation with mode `0600`, rather than relying on the process umask. - Write to a securely created temporary file in the same private directory, flush and synchronize it, then atomically replace the destination. - Refuse symbolic links and verify that existing files are regular files owned by the current user. - Replace pickle with a non-executable serialization format. - Document token revocation procedures and minimize the OAuth scopes associated with the stored refresh token. - Consider an operating-system credential store or keyring instead of a plaintext filesystem credential cache. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
book_meeting.py:33
Finding
Google Calendar OAuth Authorization Exceeds Demonstrated Functional Requirements<![CDATA[ ## Vulnerability Details **File Location**: `book_meeting.py:33-37` **Vulnerability Type**: Excessive OAuth permissions **Risk Level**: Medium ### Vulnerable Code ```python SCOPES = [ 'https://www.googleapis.com/auth/calendar.events', 'https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/meetings.space.settings' ] ``` ### Technical Analysis The Skill requests both `calendar.events` and the broader `calendar` scope. The implementation shown only inserts an event into the user's primary calendar. The broad Calendar scope overlaps with and exceeds the narrower event-management scope, while no audited operation demonstrates a need for full Calendar access. This violates least-privilege principles. It also increases the consequences of token disclosure, unsafe pickle exploitation, or compromise of the running process. The Meet settings scope is directly related to the declared behavior of configuring Meet access, but the additional broad Calendar scope is not justified by the implementation. ### Attack Path 1. The user runs the Skill and is presented with an OAuth consent flow containing all configured scopes. 2. The user grants the broad Calendar authorization. 3. An attacker obtains the cached OAuth refresh token, compromises the process, or exploits the unsafe pickle-loading vulnerability. 4. The attacker requests or uses an access token containing the broad Calendar scope. 5. The attacker performs Calendar API operations beyond the narrow event-creation behavior required by the Skill. ### Impact Assessment A compromised token or process receives broader access to the user's Google Calendar account than the declared task requires. Depending on Google's authorization semantics and API enforcement, this can expose additional calendar metadata and permit broader calendar operations. The issue does not bypass Google's consent process, but it unnecessarily expands the authorization and impact boundary. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `https://www.googleapis.com/auth/calendar` unless a documented API operation demonstrably requires it. - Retain only the narrowest scopes required for event creation and Meet access configuration. - Test event insertion using `calendar.events` and the required Meet scope before release. - Document why each remaining scope is required and which API call consumes it. - When changing scopes, invalidate or migrate existing cached credentials so users reauthorize with the reduced scope set. - Add an automated check that detects unexpected additions to the OAuth scope list. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:4
Finding
Unbounded Dependency Versions Produce Non-Reproducible Installations<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:4-6` **Vulnerability Type**: Unpinned third-party dependencies **Risk Level**: Low ### Vulnerable Code ```text google-auth>=2.0.0 google-auth-oauthlib>=1.0.0 google-api-python-client>=2.0.0 ``` ### Technical Analysis The dependency declarations specify only minimum versions and have no upper bounds, exact pins, lock file, or package hashes. Each installation can therefore resolve to different future releases that were not part of the audited artifact. The listed packages use expected official names, and no evidence of typosquatting, dependency confusion, or an unsafe package source was found. The risk arises from allowing unreviewed future versions and transitive dependency changes to enter the execution environment automatically. ### Attack Path 1. The user follows the documented command `pip install -r requirements.txt`. 2. The package resolver selects the newest releases satisfying the open-ended minimum constraints. 3. A future direct or transitive dependency release contains a compromise, exploitable defect, or unexpected behavior. 4. The package is installed without being constrained to an audited version or verified against a recorded hash. 5. Malicious installation hooks or runtime code execute with the privileges of the installing or invoking user. ### Impact Assessment The primary impact is loss of build reproducibility and exposure to unreviewed supply-chain changes. If a resolved dependency is compromised, code could execute under the installing user's privileges and access the same local files, OAuth credentials, and network resources as the Skill. No currently malicious package is established by the audited files, so the present risk level is low. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin direct dependencies to reviewed versions. - Generate a lock file that records resolved transitive dependency versions. - Require package hashes during installation, for example through a hash-locked requirements file. - Use an automated dependency update process that runs security scans and compatibility tests before accepting new versions. - Periodically refresh pinned versions to receive security fixes rather than leaving dependencies permanently stale. - Install packages from a trusted, explicitly configured package index. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose says the skill creates Google Meet spaces with OPEN access, but the document also describes the ability to create TRUSTED and RESTRICTED meetings and to use OAuth credentials with local token storage. This mismatch can mislead users and policy engines about what the skill actually does, increasing the chance of unsafe approval or misuse of privileged Google account access.

Credential Access

High
Category
Privilege Escalation
Content
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
"google-auth-oauthlib",
                "google-api-python-client",
              ],
            "files": ["client_secrets.json", "book_meeting.py"],
            "primaryEnv": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"],
            "writes": ["meeting_token.pickle"],
          },
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
default_paths = [
        'client_secrets.json',
        'credentials.json',
        os.path.expanduser('~/.config/google-meet/client_secrets.json'),
        os.path.expanduser('~/.config/google-meet/credentials.json'),
    ]
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
default_paths = [
        'client_secrets.json',
        'credentials.json',
        os.path.expanduser('~/.config/google-meet/client_secrets.json'),
        os.path.expanduser('~/.config/google-meet/credentials.json'),
    ]
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares capabilities that require environment access, file reads, local token writes, and outbound network use, but it does not explicitly declare tool scope or permissions. In an agent ecosystem, this weakens transparency and consent boundaries, making it easier for a user or orchestrator to invoke a credentialed workflow without clearly understanding the access being granted.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Defaulting meetings to OPEN means anyone with the link may join, which creates a real privacy and confidentiality risk if users assume normal invite-only behavior. In a scheduling skill, this context makes the issue more dangerous because the insecure default directly affects real meetings and can expose internal discussions to unintended participants.

Session Persistence

Medium
Category
Rogue Agent
Content
#!/usr/bin/env python3
"""Create a scheduled Google Calendar event with OPEN access Meet space.

Workflow:
1. Create Calendar event with Meet conference (Calendar API)
Confidence
82% confidence
Finding
The skill is explicitly designed to create Google Meet spaces with OPEN access, which weakens meeting access controls and increases the chance of unintended attendance, link-sharing abuse, or meeting disruption. In this skill context, that behavior is the core function, so it materially increases risk compared with a normal scheduling tool even if it is not covertly malicious.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Content
if os.path.exists(token_path):
        with open(token_path, 'rb') as token:
            creds = pickle.load(token)

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
Confidence
97% confidence
Finding
The script deserializes OAuth credentials from a pickle file using pickle.load(), which can execute arbitrary code if the file is replaced or tampered with. In this skill’s context, the token path is user-controlled and defaults to a local file, so any attacker who can plant or swap that file can achieve code execution when the script starts.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script silently writes refreshed OAuth credentials to disk, creating a persistent token that may outlive the session and be exposed through weak filesystem permissions, backups, or shared workspaces. Because the stored token grants Google Calendar and Meet access, theft of the file can enable unauthorized meeting and calendar actions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# Required packages for book-google-meet
# Install with: pip install -r requirements.txt

google-auth>=2.0.0
google-auth-oauthlib>=1.0.0
google-api-python-client>=2.0.0
Confidence
95% confidence
Finding
The dependency is specified with only a lower bound, which allows installation of any newer version, including potentially incompatible or compromised releases. This weakens build reproducibility and increases supply-chain risk if a malicious or vulnerable upstream version is pulled in later.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# Install with: pip install -r requirements.txt

google-auth>=2.0.0
google-auth-oauthlib>=1.0.0
google-api-python-client>=2.0.0
Confidence
95% confidence
Finding
Using an unpinned minimum version permits dependency drift over time, so future installations may resolve to unexpected versions with security flaws or breaking behavior. For an OAuth-related library, this can indirectly affect authentication flows if a bad upstream release is consumed.

Unpinned Dependencies

Low
Category
Supply Chain
Content
google-auth>=2.0.0
google-auth-oauthlib>=1.0.0
google-api-python-client>=2.0.0
Confidence
95% confidence
Finding
This package is also unpinned, meaning the environment may install different versions across deployments and over time. Because this client library interacts with Google APIs used to create calendar events and Meet links, an unsafe upstream release could affect sensitive scheduling functionality or credential-handling paths.

Static analysis

No suspicious patterns detected.