T09 · Insecure Skill Coding Practices
- Location
book_meeting.py:132- Finding
Unsafe Deserialization of a User-Controllable OAuth Token File
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
book_meeting.py:132Unsafe Deserialization of a User-Controllable OAuth Token File
book_meeting.py:145OAuth Refresh Token Written Without Enforced Restrictive Permissions
book_meeting.py:33Google Calendar OAuth Authorization Exceeds Demonstrated Functional Requirements
requirements.txt:4Unbounded Dependency Versions Produce Non-Reproducible Installations
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.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"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"],
},
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
default_paths = [
'client_secrets.json',
'credentials.json',
os.path.expanduser('~/.config/google-meet/client_secrets.json'),
os.path.expanduser('~/.config/google-meet/credentials.json'),
]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
default_paths = [
'client_secrets.json',
'credentials.json',
os.path.expanduser('~/.config/google-meet/client_secrets.json'),
os.path.expanduser('~/.config/google-meet/credentials.json'),
]
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.
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.
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.
#!/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)
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.
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:
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.
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.
# 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
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.
# 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
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.
google-auth>=2.0.0
google-auth-oauthlib>=1.0.0
google-api-python-client>=2.0.0
No suspicious patterns detected.