Back to skill

Security audit

Jetlag Planner

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it uses broad Google Calendar access, automatically writes many calendar events, and gives unsafe credential setup guidance.

Review this carefully before installing. Use fresh Google OAuth credentials created specifically for this skill, do not ask another bot to print secrets, and expect the tool to read your primary calendar and automatically add multiple events. Prefer running it manually first, reviewing what it creates, restricting token file permissions, and revoking the Google authorization if you stop using it.

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

Warning
Location
README.md:13
Finding

OAuth Client Secret Disclosure Through Agent Conversation

Content
View full analysis
"What is your Google Client ID and Secret from your config?" ``` ### Technical Analysis The setup procedure explicitly instructs the user to ask an AI agent to retrieve and disclose an existing Google OAuth client secret. This moves credential material from its original configuration boundary into the conversation channel. Conversation content may be retained in local logs, remote service telemetry, message history, debugging traces, or screenshots. The disclosure is unnecessary: users can create dedicated OAuth credentials or transfer credentials directly into a protected configuration file without exposing them to the agent conversation. A desktop OAuth client secret is not generally treated as a sufficient standalone authenticator, so possession of this value alone does not automatically grant Calendar access. Nevertheless, disclosure can facilitate OAuth client impersonation, abuse of the associated project, or a broader compromise when combined with authorization codes, redirect manipulation, or other leaked OAuth material. ### Attack Path 1. The user follows the README and asks the agent to print the Google Client ID and client secret. 2. The agent retrieves the values from its configuration and includes them in a response. 3. The response is retained in conversation history, logs, telemetry, or another accessible storage location. 4. An attacker with access to that location extracts the OAuth client credentials. 5. The attacker uses the credentials to impersonate the OAuth client or combines them with separately obtained OAuth authorization material. 6. If a usable authorization code or token is also obtained, the attacker can access reso ...[truncated 630 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:42
Finding

OAuth Tokens Stored Without Explicit Restrictive File Permissions

Content
View full analysis
token.expiry_date - 60_000) { const { credentials } = await auth.refreshAccessToken(); fs.writeFileSync(TOKEN_PATH, JSON.stringify(credentials)); auth.setCredentials(credentials); } return auth; } const authUrl = auth.generateAuthUrl({ access_type: 'offline', scope: SCOPES }); console.log('\n► Open this URL in your browser:\n'); console.log(' ' + authUrl + '\n'); const opened = await open(authUrl).then(() => true).catch(() => false); if (opened) { console.log('(Browser window opened)'); } else { console.log('(Could not open browser automatically — paste the URL above into your browser manually)'); } console.log('\nAfter you click "Allow", Google will show you a short code.'); const code = await promptLine('Paste the code here and press Enter: '); const { tokens } = await auth.getToken(code.trim()); fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens)); ``` ### Technical Analysis The application stores Google OAuth credentials, potentially including an offline refresh token, as plaintext JSON in `.oauth-token.json`. Both initial creation and refresh use `fs.writeFileSync` without an explicit owner-only mode. For a newly created file, Node.js uses a default mode subject to the process umask. Depending on the environment, this can leave the file readable by other local users or processes. When updating an existing file, the application also does not verify whether its current ownership and permissions are safe. This violates least-privilege handling for reusable authentication material. The risk is particularly significant because `access_type: ...[truncated 1368 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
package.json:10
Finding

Non-Reproducible Dependency Resolution Due to Mutable Version Ranges and Missing Lockfile

Content
View full analysis
Remediation
View remediation
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (30)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The README instructs users to ask another bot to reveal its configured Google Client ID and Client Secret, which normalizes exfiltrating secrets from a separate system. Even if these are OAuth client credentials rather than end-user tokens, directing a user to retrieve and reuse secrets from another agent breaks credential-boundary expectations and can expose credentials beyond their intended scope.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Telling users to ask another bot to disclose its stored Google OAuth client ID and secret is an explicit instruction to retrieve sensitive credentials from a different application context. This encourages unsafe secret disclosure patterns and could train users to bypass access controls or reuse credentials across unrelated components.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 23)May include surrounding context.

git clone https://github.com/chadholdorf/openclaw-jetlag.git cd openclaw-jetlag npm install cp .env.example .env

text

Open `.env` and paste in the values your Claw bot gave you:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 51)May include surrounding context.

git clone https://github.com/chadholdorf/openclaw-jetlag.git cd openclaw-jetlag npm install cp .env.example .env

text

Open `.env` and paste in the values your Claw bot gave you:

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill's declared description understates its actual behavior: it checks for credentials, triggers an OAuth authorization flow, and causes a local Node program to access and modify Google Calendar data. This mismatch undermines informed consent and hides sensitive data access plus write actions behind a seemingly simple travel-planning description.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · SKILL.md (reported line 8)May include surrounding context.

md
Run the jetlag planner by following these steps exactly.

## Step 1 — Check for .env

Check whether the file `~/openclaw-jetlag/.env` exists.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 83)May include surrounding context.

js
Run the jetlag planner by following these steps exactly.

## Step 1 — Check for .env

Check whether the file `~/openclaw-jetlag/.env` exists.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 85)May include surrounding context.

js
Run the jetlag planner by following these steps exactly.

## Step 1 — Check for .env

Check whether the file `~/openclaw-jetlag/.env` exists.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 98)May include surrounding context.

js
Run the jetlag planner by following these steps exactly.

## Step 1 — Check for .env

Check whether the file `~/openclaw-jetlag/.env` exists.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 104)May include surrounding context.

js
Run the jetlag planner by following these steps exactly.

## Step 1 — Check for .env

Check whether the file `~/openclaw-jetlag/.env` exists.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 26)May include surrounding context.

js
function getOAuthClient() {
  const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI } = process.env;
  if (!GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET) {
    console.error('Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in .env');
    process.exit(1);
  }
  return new google.auth.OAuth2(

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 82)May include surrounding context.

js
function getOAuthClient() {
  const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI } = process.env;
  if (!GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET) {
    console.error('Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in .env');
    process.exit(1);
  }
  return new google.auth.OAuth2(

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · index.js (reported line 84)May include surrounding context.

js
function getOAuthClient() {
  const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI } = process.env;
  if (!GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET) {
    console.error('Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in .env');
    process.exit(1);
  }
  return new google.auth.OAuth2(

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README emphasizes automatic detection and automatic writing of 14+ events to the user's calendar without a prominent warning that the skill will modify calendar data. In a skill context, silent or under-disclosed write behavior is risky because users may invoke it expecting analysis only, not persistent changes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrase examples are broad and action-oriented, increasing the chance the skill is invoked unintentionally in normal conversation. Because the skill performs write actions against a Google Calendar, accidental invocation can lead to unwanted calendar modifications without clear confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README describes scanning the primary Google Calendar via OAuth but does not provide a clear privacy notice about what data is accessed, how long tokens are stored, and what is sent or retained. This matters more here because the skill processes personal travel itinerary data and persists authorization in a local token file.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill instructs the agent to inspect local files and run local code, but it declares no explicit tool scope or allowed tools. This creates an undeclared capability boundary where a user may invoke filesystem and execution behavior without clear permissioning or review, increasing the risk of unintended local access and side effects.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad enough to match ordinary travel-related conversation, which raises the chance of accidental invocation. Because invocation leads to credential checks and local code execution with calendar access, an unintended trigger could cause privacy-impacting actions without deliberate user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description does not clearly warn that the skill will inspect Google Calendar-related setup, use stored OAuth credentials, and write new events back to the user's calendar. In a skill that processes private travel data and modifies a personal calendar, missing disclosure materially increases consent and privacy risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill automatically inserts multiple calendar events after detecting possible flights, without any explicit confirmation, preview, or per-flight approval from the user. Because it uses broad calendar write access and heuristic flight detection, a mistaken match or unexpected parse can silently modify the user's primary calendar and create unwanted reminders or clutter at scale.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The package description advertises automatic scanning of Google Calendar and writing data back to it, but it does not mention any invocation limits, explicit confirmation, or scope restrictions. In a skill context that handles personal calendar data, broad read/write behavior increases the risk of over-collection or unintended modification if the implementation follows the description literally.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest describes a calendar-scanning and plan-writing skill, but does not indicate any need to read local environment secrets or guide the user through credential bootstrap. While OAuth is a plausible implementation detail for Google Calendar access, directly consuming local client credentials from .env adds a capability outside the user-facing purpose of jetlag planning itself.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The natural-language description is platform-specific and presumes interaction with Google Calendar as the default behavior. If organizational policy requires avoiding forced platform or locale constraints without user opt-in, this wording can be read as mandating a specific service rather than offering a choice.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
83% confidence
Finding

Using a caret range for dotenv allows future compatible releases to be installed without explicit review, which weakens supply-chain integrity and reproducibility. While dotenv is not especially high risk here, unpinned dependencies can still introduce vulnerable or unexpected code into the skill.

Content

Scanner excerpt · package.json (reported line 11)May include surrounding context.

json
"start": "node index.js"
  },
  "dependencies": {
    "dotenv": "^16.4.5",
    "googleapis": "^144.0.0",
    "luxon": "^3.5.0",
    "open": "^10.1.0"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The googleapis dependency is not pinned, so builds may resolve to different releases over time, increasing supply-chain risk for a package that likely handles OAuth tokens and calendar read/write access. Because this skill accesses sensitive personal data and may modify calendar entries, dependency drift is more dangerous than in a non-privileged utility.

Content

Scanner excerpt · package.json (reported line 12)May include surrounding context.

json
},
  "dependencies": {
    "dotenv": "^16.4.5",
    "googleapis": "^144.0.0",
    "luxon": "^3.5.0",
    "open": "^10.1.0"
  },

Static analysis

No suspicious patterns detected.