Back to skill

Security audit

Praxis Google Workspace

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent Google Workspace CLI, but it asks for sensitive Google account access and has material safety gaps around OAuth warning handling and local token storage.

Review this before installing if you plan to connect a real Google account. Use a least-privilege Google account or test Workspace project, verify the OAuth client yourself before bypassing any Google warning, restrict access to ~/.config/praxis-gws, and revoke the OAuth grant if the token may have been exposed. Prefer a pinned local dependency install over the documented global npm install.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/praxis-gws.js:24
Finding

OAuth credentials and tokens are stored without explicit restrictive filesystem permissions

Content
View full analysis
{ if (err) { console.error('Error retrieving access token', err); process.exit(1); } oAuth2Client.setCredentials(token); fs.writeFileSync(TOKEN_PATH, JSON.stringify(token)); console.log('Token stored to', TOKEN_PATH); resolve(oAuth2Client); }); ``` ```js credentials(srcPath) { if (!fs.existsSync(srcPath)) { console.error('Error: File not found:', srcPath); process.exit(1); } fs.copyFileSync(srcPath, CREDENTIALS_PATH); console.log('Credentials saved to', CREDENTIALS_PATH); console.log('Run any command to start OAuth flow'); }, ``` ### Technical Analysis The configuration directory, OAuth client credentials, and OAuth token are created or copied without explicitly enforcing owner-only permissions. Their effective permissions consequently depend on the process umask and, for copied credentials, filesystem behavior and source-file metadata. `token.json` may contain a long-lived refresh token in addition to a temporary access token. The credentials file contains the OAuth client identifier and client secret. On a multi-user host, container, shared workspace, or environment with a permissive umask, another local account or compromised process may be able to read these files. The implementation also does not validate that the sensitive paths are regular files owned by the current user or reject symbolic links before readi ...[truncated 1573 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
SKILL.md:157
Finding

Google API dependency is installed globally without version or integrity pinning

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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill instructs users to bypass Google's unverified-app warning by clicking through an 'unsafe' prompt, without any compensating security validation steps. This normalizes ignoring platform security warnings and can lead users to authorize a malicious or misconfigured OAuth client with access to email, calendar, and drive data.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/praxis-gws.js

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

md
const CONFIG_DIR = path.join(process.env.HOME || '/tmp', '.config', 'praxis-gws');
const TOKEN_PATH = path.join(CONFIG_DIR, 'token.json');
const CREDENTIALS_PATH = path.join(CONFIG_DIR, 'credentials.json');

// Ensure config directory exists
fs.mkdirSync(CONFIG_DIR, { recursive: 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 · scripts/praxis-gws.js (reported line 20)May include surrounding context.

js
const CONFIG_DIR = path.join(process.env.HOME || '/tmp', '.config', 'praxis-gws');
const TOKEN_PATH = path.join(CONFIG_DIR, 'token.json');
const CREDENTIALS_PATH = path.join(CONFIG_DIR, 'credentials.json');

// Ensure config directory exists
fs.mkdirSync(CONFIG_DIR, { recursive: 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 · scripts/praxis-gws.js (reported line 28)May include surrounding context.

js
const CONFIG_DIR = path.join(process.env.HOME || '/tmp', '.config', 'praxis-gws');
const TOKEN_PATH = path.join(CONFIG_DIR, 'token.json');
const CREDENTIALS_PATH = path.join(CONFIG_DIR, 'credentials.json');

// Ensure config directory exists
fs.mkdirSync(CONFIG_DIR, { recursive: 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 · SKILL.md (reported line 31)May include surrounding context.

md
function loadCredentials() {
  if (!fs.existsSync(CREDENTIALS_PATH)) {
    console.error('Error: credentials.json not found.');
    console.error('Run: praxis-gws auth credentials /path/to/client_secret.json');
    process.exit(1);
  }
  return JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));

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

md
function loadCredentials() {
  if (!fs.existsSync(CREDENTIALS_PATH)) {
    console.error('Error: credentials.json not found.');
    console.error('Run: praxis-gws auth credentials /path/to/client_secret.json');
    process.exit(1);
  }
  return JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));

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/praxis-gws.js (reported line 29)May include surrounding context.

js
function loadCredentials() {
  if (!fs.existsSync(CREDENTIALS_PATH)) {
    console.error('Error: credentials.json not found.');
    console.error('Run: praxis-gws auth credentials /path/to/client_secret.json');
    process.exit(1);
  }
  return JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));

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/praxis-gws.js (reported line 76)May include surrounding context.

js
rl.close();
      oAuth2Client.getToken(code, (err, token) => {
        if (err) {
          console.error('Error retrieving access token', err);
          process.exit(1);
        }
        oAuth2Client.setCredentials(token);

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill exposes capabilities that can access environment-derived secrets or runtime configuration, but it does not declare any explicit tool scope or permission boundary. In a skill that handles Gmail, Calendar, and Drive, missing scope documentation increases the risk of unintended data access and makes it harder for users or reviewers to understand what the skill can actually reach.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation describes access to highly sensitive Gmail, Calendar, and Drive data but does not give a clear privacy warning about the breadth of access, token storage, or the consequences of authorizing the app. Users may grant broad OAuth scopes without understanding that email contents, calendar events, and file metadata or contents could be exposed through the CLI.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
## Setup

### 1. Create Google Cloud Project

1. Go to https://console.cloud.google.com
2. Create a new project

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code persists the Google OAuth token to a local file, which is a safety-relevant credential-handling action. While it logs the storage path after writing, there is no prior disclosure in comments, help text, or prompts warning users that authentication tokens will be stored on disk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill defaults calendar event creation to the America/Phoenix timezone when the user does not specify one. This imposes a locale-specific behavior without opt-in, which can violate language/locale policy expectations and lead to incorrect event scheduling for users in other regions.

Content

No source excerpt is available for this finding.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Content

Scanner excerpt · scripts/praxis-gws.js (reported line 286)May include surrounding context.

js
}
    fs.copyFileSync(srcPath, CREDENTIALS_PATH);
    console.log('Credentials saved to', CREDENTIALS_PATH);
    console.log('Run any command to start OAuth flow');
  },
  
  async status() {

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The command-line handler injects America/Phoenix as the default timezone for calendar creation when --timezone is omitted. This is a locale-specific default applied silently, rather than offering user choice or using account-local settings.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.