Back to skill

Security audit

Google Tasks

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Google Tasks integration, but it handles OAuth tokens and local authentication in ways users should review before trusting it.

Install only if you are comfortable granting full read/write Google Tasks access. Keep credentials.json and token.json out of shared workspaces, set restrictive file permissions manually, verify which directory the scripts are using for tokens, and consider hardening or replacing the custom Node OAuth flow before use.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/auth.mjs:47
Finding

OAuth callback accepts uncorrelated authorization codes on a network-accessible listener

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.mjs:47-74; scripts/refresh_token.js:70-134
Vulnerability Type: OAuth login CSRF and insecure local callback listener
Risk Level: High

Vulnerable Code

scripts/auth.mjs:47-74:

javascript
async function getNewToken(oauth2Client) {
  return new Promise((resolve, reject) => {
    const authUrl = oauth2Client.generateAuthUrl({
      access_type: 'offline',
      scope: SCOPES,
    });

    const server = http.createServer(async (req, res) => {
      try {
        const qs = new url.URL(req.url, 'http://localhost:3000').searchParams;
        const code = qs.get('code');
        
        if (code) {
          res.end('✅ Authentication successful! You can close this window.');
          server.close();
          
          const { tokens } = await oauth2Client.getToken(code);
          oauth2Client.setCredentials(tokens);
          resolve(tokens);
        }
      } catch (e) {
        reject(e);
      }
    }).listen(3000, () => {
      console.log('🌐 Opening browser for authentication...');
      console.log(`If browser doesn't open, visit: ${authUrl}`);
      open(authUrl);
    });
  });
}

scripts/refresh_token.js:70-134:

javascript
const SCOPES = ['https://www.googleapis.com/auth/tasks'];
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${new url.URLSearchParams({
  client_id,
  redirect_uri: redirect_uris[0],
  response_type: 'code',
  scope: SCOPES.join(' '),
  access_type: 'offline',
  prompt: 'consent'
}).toString()}`;

console.log('\n📋 Authorize this app by visiting:\n');
console.log(authUrl);
console.log('\n');

// Start local server to receive callback
const server = http.createServer(async (req, res) => {
  if (req.url.indexOf('/?code=') > -1) {
    const qs = new url.URL(req.url, 'http://localhost:3000').searchParams;
    const code = qs.get('code');
    
    res.end('✅ Authentication successful! You can close this window.');
    
    // Exchange code 
...[truncated 4256 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the custom OAuth implementation with a maintained installed-application flow from Google's authentication library where possible.
  2. Generate at least 32 bytes of cryptographically secure random data for each authorization attempt:
javascript
import crypto from 'crypto';

const state = crypto.randomBytes(32).toString('base64url');
  1. Include state in the authorization URL and require an exact, timing-safe match at the callback.
  2. Bind explicitly to a loopback address and preferably use an ephemeral port:
javascript
server.listen(0, '127.0.0.1', () => {
  const { port } = server.address();
});
  1. Construct the redirect URI from the actual loopback port and ensure it is permitted by the installed-application OAuth client configuration.
  2. Validate that the request uses GET and that the pathname exactly matches the configured callback path.
  3. Reject callbacks containing error, missing code, duplicate parameters, or invalid state.
  4. Add a short timeout that closes the server and invalidates the pending state.
  5. Add PKCE with an S256 code challenge where supported.
  6. Remove or deprecate the duplicate refresh_token.js flow so that only one hardened authentication implementation is exposed to users.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.mjs:42
Finding

OAuth tokens are written without enforcing owner-only file permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/auth.mjs:42-44; scripts/auth.py:57-60; scripts/refresh_token.js:42-47,112-118; scripts/refresh_token.sh:56-61
Vulnerability Type: Insecure storage of OAuth access and refresh tokens
Risk Level: Medium

Vulnerable Code

scripts/auth.mjs:42-44:

javascript
async function saveToken(token) {
  await fs.writeFile(TOKEN_PATH, JSON.stringify(token, null, 2));
  console.log(`✅ Token saved to ${TOKEN_PATH}`);
}

scripts/auth.py:57-60:

python
# Save credentials for future use
with open(token_path, 'w') as token:
    token.write(creds.to_json())
print(f"✅ Token saved to {token_path}")

scripts/refresh_token.js:42-47:

javascript
const newToken = JSON.parse(data);
if (newToken.access_token) {
  token.access_token = newToken.access_token;
  token.expiry_date = Date.now() + (newToken.expires_in * 1000);
  fs.writeFileSync(TOKEN_PATH, JSON.stringify(token, null, 2));
  console.log('✅ Token refreshed successfully!');
  process.exit(0);
}

scripts/refresh_token.js:112-118:

javascript
const tokenReq = https.request(options, (tokenRes) => {
  let data = '';
  tokenRes.on('data', (chunk) => { data += chunk; });
  tokenRes.on('end', () => {
    const token = JSON.parse(data);
    fs.writeFileSync(TOKEN_PATH, JSON.stringify(token, null, 2));
    console.log('✅ Token saved to', TOKEN_PATH);

scripts/refresh_token.sh:56-61:

bash
# Update token.json with new access token and expiry
EXPIRY_DATE=$(($(date +%s) * 1000 + 3600000))  # Current time + 1 hour in milliseconds

jq --arg token "$NEW_ACCESS_TOKEN" --arg expiry "$EXPIRY_DATE" \
    '.access_token = $token | .expiry_date = ($expiry | tonumber)' \
    "$TOKEN_FILE" > "$TOKEN_FILE.tmp" && mv "$TOKEN_FILE.tmp" "$TOKEN_FILE"

Technical Analysis

The authentication implementations store bearer access tokens and potentially long-lived refresh tokens in plaintext token.json. None of the implementations explicitly en ...[truncated 2796 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create token files with mode 0600 and verify permissions after every write.

For Node.js:

javascript
await fs.writeFile(
  TOKEN_PATH,
  JSON.stringify(token, null, 2),
  { encoding: 'utf8', mode: 0o600 }
);
await fs.chmod(TOKEN_PATH, 0o600);

For Python:

python
fd = os.open(token_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, 'w', encoding='utf-8') as token:
    token.write(creds.to_json())
os.chmod(token_path, 0o600)
  1. In shell code, set a restrictive umask before creating any credential-bearing file:
bash
umask 077
  1. Replace the predictable temporary file with mktemp in the same protected directory, install a cleanup trap, and explicitly set its mode:
bash
umask 077
tmp_file=$(mktemp "$SKILL_DIR/.token.json.XXXXXX")
trap 'rm -f "$tmp_file"' EXIT

jq --arg token "$NEW_ACCESS_TOKEN" --arg expiry "$EXPIRY_DATE" \
  '.access_token = $token | .expiry_date = ($expiry | tonumber)' \
  "$TOKEN_FILE" > "$tmp_file"

chmod 600 "$tmp_file"
mv -f "$tmp_file" "$TOKEN_FILE"
trap - EXIT
  1. Before reading tokens, reject files that are symlinks, are not owned by the current user, or are accessible by group/other users.
  2. Store tokens in an operating-system credential store or encrypted secret service when available.
  3. Ensure the containing directory is owner-controlled and not a shared or globally writable workspace.
  4. Document token revocation procedures and instruct users to revoke the Google OAuth grant if token.json may have been exposed.
  5. Apply equivalent protections to credentials.json, which contains the OAuth client secret.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (45)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a complete Google Tasks skill with API operations and OAuth automation. However, the supplied code chunk is only a minimal configuration file containing a DEFAULT_LIST variable. It does not itself fetch, display, create, or delete tasks, authenticate, or call the Google Tasks API. Based on the provided chunk alone, the description materially overstates the implemented behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code chunk is limited to read/display behavior: it validates the presence of token.json, extracts an access token, calls the Google Tasks API to list task lists and tasks, and prints them. There are no API calls that create or delete tasks, and no authentication flow is implemented in this chunk beyond reading an existing token file. Because the declared description claims broader capabilities (create/delete and automatic OAuth handling) that are not represented by the supplied code, the description does not accurately match the actual behavior of this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This is a clear description/behavior mismatch. The declared purpose says the skill manages Google Tasks themselves (list/get/add/delete) using the Google Tasks API. However, the provided code chunk is strictly an authentication helper script. Its primary function is to refresh an OAuth access token or perform the full OAuth consent flow, including opening the authorization URL, listening on localhost:3000 for the callback, exchanging the code for tokens, and writing token data to disk. Those auth steps are supportive infrastructure, but because this code chunk contains none of the actual Google Tasks operations described, the supplied behavior does not accurately represent the declared end-user functionality.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The documentation requires a valid token.json with an OAuth access token and requests read/write Google Tasks scope, which confirms the skill handles live bearer credentials. If the skill or surrounding agent environment reads, stores, or exposes these tokens insecurely, an attacker could impersonate the user against the Google Tasks API.

Content

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

md
- `jq` - JSON processor (usually pre-installed)
- `curl` - HTTP client (usually pre-installed)
- Valid `token.json` with OAuth access token
- **Scopes required:** `https://www.googleapis.com/auth/tasks` (read + write)

## First-Time Setup

Credential Access

High
Category
Privilege Escalation
Confidence
81% confidence
Finding

The skill explicitly relies on local OAuth credential material such as credentials.json and token.json, indicating access to sensitive authentication artifacts. In an agent or shared workspace context, exposing or broadly accessing these files can enable token theft, unauthorized API use, or persistence via refresh tokens.

Content

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

md
If `token.json` doesn't exist:

1. User needs OAuth credentials (`credentials.json`) - See [setup.md](references/setup.md)
2. Run the Node.js authentication flow first to generate `token.json`
3. Then the bash script can be used for all subsequent calls

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 · CLAWHUB_CHECKLIST.md (reported line 41)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · CLAWHUB_CHECKLIST.md (reported line 100)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · CLAWHUB_CHECKLIST.md (reported line 109)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · CLAWHUB_CHECKLIST.md (reported line 110)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · README.md (reported line 54)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · README.md (reported line 85)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · references/setup.md (reported line 10)May include surrounding context.

md
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.mjs (reported line 19)May include surrounding context.

js
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.mjs (reported line 27)May include surrounding context.

js
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.py (reported line 20)May include surrounding context.

python
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.py (reported line 23)May include surrounding context.

python
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.py (reported line 27)May include surrounding context.

python
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/auth.py (reported line 29)May include surrounding context.

python
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/get_tasks.sh (reported line 2)May include surrounding context.

sh
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/refresh_token.js (reported line 7)May include surrounding context.

js
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/refresh_token.sh (reported line 9)May include surrounding context.

sh
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/refresh_token.sh (reported line 18)May include surrounding context.

sh
#!/bin/bash
# Fetch Google Tasks using credentials.json and token.json

set -euo pipefail

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 · scripts/create_task.sh (reported line 55)May include surrounding context.

sh
#!/bin/bash
# Refresh Google OAuth access token using refresh_token

set -euo pipefail

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 · scripts/delete_task.sh (reported line 29)May include surrounding context.

sh
#!/bin/bash
# Refresh Google OAuth access token using refresh_token

set -euo pipefail

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 · scripts/get_tasks.sh (reported line 16)May include surrounding context.

sh
#!/bin/bash
# Refresh Google OAuth access token using refresh_token

set -euo pipefail

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/refresh_token.js:133

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/refresh_token.js:44