Back to skill

Security audit

Openclaw with Remember The Milk

Security checks for vulnerabilities and agentic risk

Overview

This RTM task skill appears purpose-aligned, but it should go to Review because it stores and handles account credentials/tokens and can modify or delete remote tasks without strong safeguards.

Install only if you trust this skill with your Remember The Milk account. Prefer environment variables or a credential manager over typing secrets into rtm config, restrict access to any ~/.rtm-*.json files, avoid using it from automated agents that might delete tasks without review, and consider rotating credentials if full RTM request URLs or config commands have been logged.

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

Warning
Location
index.js:103
Finding
RTM API credentials exposed through command-line arguments<![CDATA[ ## Vulnerability Details **File Location**: `index.js:103-111`; documented usage at `SKILL.md:40-43` **Vulnerability Type**: Sensitive information exposure through process arguments and shell history **Risk Level**: Medium ### Complete Code Snippet ```js if (subcmd === 'config') { const newApiKey = argv[1]; const newSecret = argv[2]; if (!newApiKey || !newSecret) { throw new Error('Provide both API Key and Shared Secret: rtm config <api_key> <shared_secret>'); } fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify({ API_KEY: newApiKey, SHARED_SECRET: newSecret }, null, 2), { mode: 0o600 }); ``` The corresponding documented command is: ```bash rtm config <your-api-key> <your-shared-secret> ``` ### Technical Analysis The recommended configuration mechanism accepts both the RTM API key and shared secret as ordinary command-line arguments. Although the destination file is created with restrictive `0600` permissions, those permissions only protect the resulting file. They do not protect credentials while they are present in the command line. Depending on the host environment, command arguments may be exposed through: - Interactive shell history. - Terminal session recording. - Process inspection while the command is running. - Endpoint monitoring and command-auditing software. - CI/CD logs or automation diagnostics. - Copy-and-paste records and support transcripts. The implementation does not redact, prompt securely for, or otherwise prevent retention of the shared secret. This is especially relevant because the documentation describes this command as the recommended setup method. ### Attack Path 1. A user follows the documentation and runs `rtm config` with the API key and shared secret directly in the command. 2. The shell, terminal recorder, process monitor, or command-auditing system records the complete invocation. 3. An attacker or lower-privileged operator with access to those records retrieves the API key and sh ...[truncated 1073 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace secret-bearing command arguments with an interactive prompt that reads the shared secret from standard input without echoing it. 2. Keep the API key as an argument only if it is explicitly considered non-secret; prompt separately for the shared secret. 3. Support loading credentials from a user-selected, permission-checked file or from standard input. 4. Prefer an operating-system credential store such as macOS Keychain, Windows Credential Manager, or a Linux secret service. 5. Update `SKILL.md` so the recommended setup procedure never places the shared secret directly in shell history. 6. Continue creating fallback credential files with `0600` permissions, and verify the file is owned by the current user before reading it. 7. Provide guidance for clearing historical commands and rotating credentials for users who previously used the vulnerable configuration method. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
rtm-client.js:23
Finding
Authentication tokens and private task data transmitted in URL query strings<![CDATA[ ## Vulnerability Details **File Location**: `rtm-client.js:23-38` **Vulnerability Type**: Sensitive information exposure through request URLs **Risk Level**: Medium ### Complete Code Snippet ```js async callApi(method, params = {}) { const fullParams = { ...params, method, api_key: this.apiKey, format: 'json', }; if (this.token && !fullParams.auth_token) { fullParams.auth_token = this.token; } fullParams.api_sig = this._signParams(fullParams); const qs = new URLSearchParams(fullParams).toString(); const url = `${this.endpoint}?${qs}`; const res = await fetch(url); ``` ### Technical Analysis Every API parameter is serialized into the URL query string. Depending on the requested operation, the resulting URL can contain: - The RTM API key. - The reusable RTM authentication token. - The API request signature. - Task names. - Note titles and note contents. - Due dates and start dates. - Task, list, series, frob, and timeline identifiers. - User-supplied search filters. The requests use HTTPS and the destination is hard-coded to the official RTM API endpoint. Therefore, this is not evidence of covert exfiltration, and passive observers cannot ordinarily read the query string in transit. Nevertheless, sensitive data in URLs can be retained by application diagnostics, HTTP client instrumentation, TLS-terminating infrastructure, security monitoring products, reverse proxies, crash reports, or error telemetry. The behavior exceeds the safest minimum disclosure mechanism because authentication material and private task content are incorporated into a commonly logged data field rather than a request body or authorization header. ### Attack Path 1. The user authorizes the Skill and invokes a command such as `rtm list`, `rtm add`, or `rtm note`. 2. `callApi` adds the user's authentication token and operation parameters to `fullParams`. 3. The method serializes all parameters into ...[truncated 1334 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use an API-supported POST request and place operation parameters, task content, and authentication material in the request body rather than the URL. 2. If supported by the RTM API, place reusable authorization material in an authorization header. 3. Preserve the API's required signing algorithm while signing the same canonical parameter set before placing those parameters in the body. 4. If the legacy RTM protocol requires query-string authentication, explicitly disable or redact URL query logging in the application, HTTP client instrumentation, proxies, and telemetry systems. 5. Implement a centralized redaction function that removes `auth_token`, `api_key`, `api_sig`, `frob`, `note_text`, `note_title`, and task content before logging request or error objects. 6. Avoid including complete request URLs in exceptions, debug output, crash reports, or observability events. 7. Rotate exposed tokens and application credentials if full URLs have previously been retained in accessible logs. 8. Document the residual privacy risk when protocol constraints prevent moving sensitive parameters out of the URL. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill presents itself as a simple RTM integration with no declared permissions, while the documented behavior includes outbound API access, local token storage, and destructive operations such as modifying and deleting tasks. This mismatch can mislead users and security systems about the real authority of the skill, increasing the chance of unauthorized or unexpected account actions.

Credential Access

High
Category
Privilege Escalation
Content
rtm config <your-api-key> <your-shared-secret>
```

This saves the credentials safely to `~/.rtm-credentials.json` ensuring they persist across terminal restarts.

### Method B: Using a `.env` file
Confidence
88% confidence
Finding
The skill instructs users to store an API key and shared secret in a predictable local file under the home directory, and labels this as safe without describing file permission requirements or OS credential-store alternatives. If that file is readable by other local processes, users, backups, or malware, the credentials could be stolen and used to access or manipulate the user's RTM account.

Credential Access

High
Category
Privilege Escalation
Content
const path = require('path');
const os = require('os');

// Load .env manually to avoid third-party dependencies
const envPath = path.join(__dirname, '.env');
if (fs.existsSync(envPath)) {
    const envFile = fs.readFileSync(envPath, 'utf8');
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const os = require('os');

// Load .env manually to avoid third-party dependencies
const envPath = path.join(__dirname, '.env');
if (fs.existsSync(envPath)) {
    const envFile = fs.readFileSync(envPath, 'utf8');
    envFile.split(/\r?\n/).forEach(line => {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const RTMClient = require('./rtm-client');

const TOKEN_FILE = path.join(os.homedir(), '.rtm-token.json');
const CREDENTIALS_FILE = path.join(os.homedir(), '.rtm-credentials.json');
const ID_CACHE_FILE = path.join(os.homedir(), '.rtm-id-cache.json');

module.exports = {
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
94% confidence
Finding
The skill documentation describes networked functionality and credential handling, but the manifest does not declare any tool scope or allowed tools. In an agent environment, missing permission declarations can cause users or orchestrators to underestimate the skill's ability to access environment data and make outbound requests, weakening trust and review controls.

Session Persistence

Medium
Category
Rogue Agent
Content
### Method B: Using a `.env` file

Create a file named `.env` in this skill's folder (you can use `.env.example` as a template) and add your keys:

```env
RTM_API_KEY="your-api-key"
Confidence
90% confidence
Finding
The documentation recommends placing long-lived API credentials in a local .env file inside the skill folder, which creates persistent secret exposure risk through accidental commits, workspace sharing, backups, or other local tooling. In agent environments, project-directory files are often more broadly accessible than users expect, making this context more dangerous.

External Transmission

Medium
Category
Data Exfiltration
Content
constructor(apiKey, sharedSecret) {
        this.apiKey = apiKey;
        this.sharedSecret = sharedSecret;
        this.endpoint = 'https://api.rememberthemilk.com/services/rest/';
        this.authEndpoint = 'https://www.rememberthemilk.com/services/auth/';
        this.token = null; // Will be set after auth
    }
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This code sends request parameters, including the API key, auth token, and user task-related data, to a remote Remember The Milk endpoint via HTTP requests. There is no confirmation prompt, logging, comment, or docstring in this file disclosing that user data and credentials are transmitted off-system.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The deleteTask method performs a destructive remote deletion of a task, but this file contains no confirmation, warning, or explanatory comment indicating that the action is irreversible or affects user data. For code files, destructive operations should have some form of user disclosure unless the warning is documented elsewhere.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The documentation exposes a delete command without clearly warning that it is destructive or may be irreversible. In an LLM-agent or CLI context, insufficient warning increases the risk of accidental data loss, especially when commands may be generated or executed quickly.

Static analysis

No suspicious patterns detected.