Back to skill

Security audit

Plutio

Security checks for vulnerabilities and agentic risk

Overview

This Plutio skill mostly matches its stated task-management purpose, but it needs review because it handles long-lived API credentials unsafely and can read or change workspace data.

Review before installing. Use a Plutio API application with the narrowest permissions possible, avoid pasting secrets into chat or putting them in command history/profile files, prefer a password manager or OS credential store, and rotate credentials if they were already used in exposed examples. Treat people-list output and task data as sensitive business data, and require explicit confirmation before bulk updates, closures, or any direct API deletion.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/plutio-cli.py:361
Finding
Plutio API credentials are exposed through command-line arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/plutio-cli.py:361-363` **Vulnerability Type**: Sensitive information exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--subdomain", required=True, help="Plutio subdomain (e.g., 'grewing')") parser.add_argument("--app-key", required=True, help="Plutio App Key") parser.add_argument("--secret", required=True, help="Plutio Secret Code") ``` The usage documentation repeatedly instructs users to invoke the program with credentials directly on the command line: ```powershell --app-key YOUR_APP_KEY ` --secret YOUR_SECRET ``` ### Technical Analysis The CLI requires the Plutio application key and client secret to be supplied as command-line arguments. Command-line arguments are not an appropriate channel for secrets because they may be exposed through: - Process inspection utilities and operating-system process APIs. - Shell command history. - Process monitoring or endpoint telemetry. - CI/CD job logs and diagnostic output. - Task scheduler configuration and automation logs. - Parent processes or other locally privileged users. Although the credentials are intentionally sent over HTTPS to the fixed Plutio OAuth endpoint, exposing them in the local process argument vector is not necessary for the declared functionality. The program could instead retrieve them directly from a protected environment variable, secret manager, OS credential store, or standard input. ### Attack Path 1. A user follows the documented examples and starts the CLI with `--app-key` and `--secret`. 2. The complete command line is recorded in shell history, automation telemetry, or the operating system's process information. 3. An attacker with access to that source extracts the Plutio client ID and client secret. 4. The attacker submits the stolen credentials to the Plutio OAuth token endpoint. 5. The attacker obtains a bearer token carrying the API application's authoriz ...[truncated 743 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make command-line secret arguments optional and discourage their use: - Read `PLUTIO_APP_KEY`, `PLUTIO_SECRET`, and `PLUTIO_SUBDOMAIN` directly inside the program. - Preserve explicit arguments only for non-sensitive configuration such as the subdomain. 2. Support secure secret sources: - OS credential managers. - Bitwarden or another secret manager. - Standard input via `getpass.getpass()` for interactive use. - Protected file descriptors for automation. 3. If legacy `--secret` support must remain, display a warning that the value may be visible in process listings and shell history. 4. Remove secret-bearing commands from documentation and examples. 5. Ensure diagnostics, telemetry, and exceptions never print credential values. 6. Rotate any credentials that may already have been entered into shared shells, CI logs, or monitored automation environments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/setup-guide.md:59
Finding
Setup documentation recommends persistent plaintext credential storage<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md:59-68` **Vulnerability Type**: Plaintext storage of long-lived API credentials **Risk Level**: Medium ### Vulnerable Documentation ```bash **Option B: Persistent Configuration (Recommended)** Add to your shell profile (`~/.zshrc`, `~/.bashrc`, or `~/.bash_profile`): ```bash # Plutio API Credentials export PLUTIO_SUBDOMAIN="your-subdomain" export PLUTIO_APP_KEY="your-client-id" export PLUTIO_SECRET="your-client-secret" ``` ``` A related scheduled PowerShell workflow also embeds credentials directly into a script: ```powershell $env:PLUTIO_SUBDOMAIN = "grewing" $env:PLUTIO_APP_KEY = "your_app_key" $env:PLUTIO_SECRET = "your_secret" ``` ### Technical Analysis The setup guide labels persistent storage of the client secret in a shell profile as “Recommended.” Shell profiles and automation scripts are ordinary plaintext files rather than protected secret stores. They may be exposed through: - Incorrect or inherited filesystem permissions. - Backups and workstation synchronization. - Support archives and diagnostic collection. - Source-control commits. - Malware operating with the user's permissions. - Administrative or shared-account access. - Script copying and accidental disclosure. The recommendation also conflicts with the guide's later instruction not to store credentials in plaintext files. Storing the client secret persistently in a profile extends its exposure from a single session to every future session and backup containing that profile. ### Attack Path 1. A user follows the recommended persistent configuration instructions. 2. The Plutio application key and secret are saved in a shell profile or scheduled-task script. 3. The file is copied into a backup, committed accidentally, synchronized, or read by another local principal or malicious process. 4. The attacker extracts the plaintext credentials. 5. The attacker exchanges the credentials for a Plutio OAuth bearer ...[truncated 717 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not describe plaintext shell-profile storage as recommended. 2. Make a dedicated secret manager or native OS credential store the primary persistent configuration method: - Bitwarden CLI. - Windows Credential Manager. - macOS Keychain. - Linux Secret Service or an equivalent protected store. 3. Retrieve credentials only when the CLI is invoked, rather than exporting them in every shell session. 4. For scheduled workflows: - Use a service account with narrowly scoped Plutio permissions. - Retrieve the secret at runtime from a protected store. - Apply restrictive ACLs to the scheduled script and task definition. 5. Remove examples that hardcode secrets in scripts. 6. Warn users not to echo credential variables during verification. 7. Add instructions for checking shell history, repositories, and logs and rotating credentials after accidental exposure. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/plutio-cli.py:67
Finding
OAuth bearer token cache is written before restrictive permissions are applied<![CDATA[ ## Vulnerability Details **File Location**: `scripts/plutio-cli.py:67-75` **Vulnerability Type**: Non-atomic creation of a sensitive token file **Risk Level**: Low ### Vulnerable Code ```python # Cache token CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(TOKEN_FILE, "w") as f: json.dump({ "token": self.access_token, "expires_at": expires_at, "credentials_hash": self._hash_credentials() }, f) TOKEN_FILE.chmod(0o600) # Restrict file permissions ``` ### Technical Analysis The bearer token is first written using `open(TOKEN_FILE, "w")`, which creates the file according to the process's current umask. The code changes the permissions to `0600` only after the complete sensitive value has been written. Consequently, a permissive or misconfigured umask can briefly produce a token file readable by other local users. The operation is also not atomic and does not explicitly reject symbolic links. Python's normal file opening behavior follows symbolic links, so a hostile local condition affecting the predictable cache path could redirect the write. The cached value is a bearer token. Possession of that value is sufficient to authenticate until the token expires; no separate proof of the client secret is required. ### Attack Path A practical exploitation path requires local access and favorable filesystem conditions: 1. The attacker determines the predictable token path: `~/.config/plutio/token.json`. 2. The victim runs the CLI while using permissive file-creation permissions, or the cache path is otherwise exposed to local manipulation. 3. The CLI writes the bearer token before applying mode `0600`. 4. The attacker reads the token during the exposure window or obtains it through a redirected cache write. 5. The attacker submits the token in an `Authorization: Bearer` header to the Plutio API. 6. The attacker accesses the victim's workspace until the token expires or is revoked. ### Impact Assessment The impact i ...[truncated 516 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the cache file with restrictive permissions from the outset rather than applying permissions after writing. 2. Use a secure file descriptor, for example with: - `os.O_WRONLY | os.O_CREAT | os.O_TRUNC` - Mode `0o600` - `os.O_NOFOLLOW` where supported 3. Write to a securely created temporary file in the same protected directory and atomically replace the destination with `os.replace`. 4. Verify that the cache directory: - Is owned by the current user. - Is not writable by group or other users. - Is not a symbolic link. 5. Reject unexpected token-file types and ownership before reading or replacing the cache. 6. Consider storing the access token in an OS credential store rather than a plaintext JSON file. 7. Delete the cache on authentication failures or detected ownership and permission anomalies. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The manifest overstates supported capabilities and omits at least one actual capability, creating a misleading trust boundary for users and agents. When a skill says it can safely manage or update resources that it does not actually support, operators may supply credentials and authorize actions under false assumptions, while undeclared behavior like listing people expands data exposure unexpectedly.

Credential Access

High
Category
Privilege Escalation
Content
- Windows PowerShell: `$env:PLUTIO_APP_KEY = "..."`
4. **Python 3** must be installed

The skill caches access tokens locally (valid for ~1 hour), then automatically refreshes when needed.

## Quick Start
Confidence
88% confidence
Finding
The documentation states that access tokens are cached locally and refreshed automatically, but it does not describe storage protections, file permissions, encryption, or cache location hardening. Because these tokens authorize API access, insecure local caching could allow other local users, malware, or over-privileged tools to steal and reuse them.

Credential Access

High
Category
Privilege Escalation
Content
## How It Works

1. **Authentication**: Exchanges app key + secret for temporary access token
2. **API Calls**: Uses token for authenticated requests to Plutio REST API
3. **Token Caching**: Stores token locally for faster subsequent calls
4. **Error Handling**: Reports API errors clearly with troubleshooting hints
Confidence
90% confidence
Finding
The authentication flow explicitly exchanges long-lived app credentials for access tokens and stores tokens locally for reuse, but the documentation does not define safeguards around those credentials or cached tokens. In the context of a project-management integration, stolen tokens or app secrets could expose project data, people lists, and permit unauthorized task operations.

Credential Access

High
Category
Privilege Escalation
Content
**Base URL**: `https://api.plutio.com/v1.8/`

**Authentication**: OAuth 2.0 (app key + secret → access token)

**Rate Limit**: 1000 calls/hour
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
**Base URL**: `https://api.plutio.com/v1.8/`

**Authentication**: OAuth 2.0 (app key + secret → access token)

**Rate Limit**: 1000 calls/hour
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
**Base URL**: `https://api.plutio.com/v1.8/`

**Authentication**: OAuth 2.0 (app key + secret → access token)

**Rate Limit**: 1000 calls/hour
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
**Base URL**: `https://api.plutio.com/v1.8/`

**Authentication**: OAuth 2.0 (app key + secret → access token)

**Rate Limit**: 1000 calls/hour
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
**Base URL**: `https://api.plutio.com/v1.8/`

**Authentication**: OAuth 2.0 (app key + secret → access token)

**Rate Limit**: 1000 calls/hour
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
## Authentication

### Generate Access Token

```
POST /tokens
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### Delete Task

```
DELETE /tasks/{taskId}
```

**Response** (204 No Content)
Confidence
95% confidence
Finding
Documenting a raw DELETE endpoint for tasks gives the skill a potentially destructive parameterizable action that can be triggered with only a task ID. Because the skill context is task management and the manifest does not declare deletion, this makes the endpoint especially risky: an agent could be induced to delete arbitrary tasks through prompt manipulation, confusion, or overbroad automation.

Missing User Warnings

High
Confidence
99% confidence
Finding
The connection test passes the app key and secret directly as command-line arguments. Process arguments are commonly visible to local users via process-listing tools and may also be captured by shell history, monitoring tools, crash reports, or orchestration logs.

Missing User Warnings

High
Confidence
99% confidence
Finding
The alias usage continues the unsafe pattern of supplying secrets via command-line flags, reinforcing insecure operational practice. Because this is presented as a convenience workflow, users are more likely to repeat it frequently, increasing the chance of credential disclosure through process inspection and logs.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### Token Cache Issues
Token is cached locally for ~1 hour. To force a refresh:
- Delete the token file and retry:
  - **macOS/Linux**: `rm ~/.config/plutio/token.json`
  - **Windows**: `Remove-Item $env:USERPROFILE\.config\plutio\token.json`

### "Rate Limited" (429 Error)
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
self.token_expires_at = None
        
    def get_token(self) -> str:
        """Get or refresh access token"""
        # Try loading from cache first
        if TOKEN_FILE.exists():
            try:
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
91% confidence
Finding
The skill declares no explicit tool scope even though its documented behavior clearly implies shell execution, network access to the Plutio API, and local file writes for token caching. Missing scope boundaries increases the chance that an agent invokes the skill with broader-than-necessary capabilities, making misuse, credential leakage, or unintended local side effects more likely.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The setup instructions include a natural-language example that tells users to paste a client ID and secret directly into chat, without warning that chat transcripts, logs, or prompts may be retained. In an agent environment, this is a real credential-handling risk because it normalizes disclosing secrets through potentially persistent channels.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The documentation says task updates are restricted or unsupported, yet earlier sections present updating and closing tasks as supported operations. This inconsistency can cause an agent or user to attempt privileged state changes with credentials they would not otherwise provide, or to rely on behavior that fails in unpredictable ways, increasing the chance of unsafe workarounds.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The skill advertises full-field task creation, but the limitations section states only title, board ID, and group ID are actually supported. This mismatch can lead users to pass sensitive task metadata or assume fields were applied when they were silently ignored, causing confidentiality, integrity, and workflow issues.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest says the skill supports creating, updating, closing, and querying tasks, but the reference additionally documents a hard delete endpoint. This undocumented destructive capability creates a scope mismatch that could let an agent perform irreversible actions users do not expect or approve.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
A destructive DELETE operation is presented without warnings about irreversibility, confirmation requirements, or safer alternatives. In an agent context, omission of such guardrails increases the chance of accidental or automated data loss from normal language requests or prompt misunderstandings.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill is described as managing projects and tasks, but the reference also exposes People endpoints that enumerate workspace users and return names, emails, roles, and status. This expands the accessible data surface beyond the declared scope and could enable unnecessary collection of personal and organizational information if an agent uses the broader reference opportunistically.

Session Persistence

Medium
Category
Rogue Agent
Content
## Workflow 2: Create a New Task from Calendar Event

When a calendar event is created, automatically add a task to Plutio:

```bash
#!/bin/bash
Confidence
80% 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.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The workflow bulk-closes tasks selected by a filter without any warning, dry-run, confirmation, or rollback guidance. In practice this can cause accidental mass state changes and operational disruption, especially if the project ID or jq filter is wrong.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest describes managing Plutio projects and tasks, with examples centered on listing projects, viewing tasks, creating tasks, updating task details, and closing tasks. This example introduces a separate `list-people` capability to enumerate people records in Plutio, which is not mentioned in the stated skill scope and expands behavior beyond project/task management.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
This example extends the skill from Plutio task management into external Matrix messaging, creating an outbound communication path not described in the skill's stated scope. Scope expansion matters because it can enable silent data exfiltration of task metadata to third-party systems and normalize chaining this skill with messaging actions outside user expectations.

Static analysis

No suspicious patterns detected.