Back to skill

Security audit

Epragma Redmine Issue

Security checks for vulnerabilities and agentic risk

Overview

This Redmine skill is review-worthy because it is presented as read-only but can make live changes to issues and time entries using a configured API key.

Install only if you intend to give this skill write access to your Redmine instance, not just read access. Use HTTPS-only Redmine URLs, a dedicated least-privilege API key, and be careful with commands that update issues, post comments, create issues, or add time entries because they modify live server data immediately.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/redmine.js:1
Finding
Redmine API credentials can be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/redmine.js:1-40` **Vulnerability Type**: Insufficient transport and destination validation for sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```js const REDMINE_URL = process.env.REDMINE_URL || process.env.REDMINE_API_KEY?.startsWith('http') || ''; const API_KEY = process.env.REDMINE_API_KEY || process.env.REDMINE_BASE_URL || ''; function getBaseUrl() { if (REDMINE_URL?.startsWith('http')) { return REDMINE_URL; } if (API_KEY?.startsWith('http')) { return API_KEY; } if (!REDMINE_URL || !API_KEY) { throw new Error('REDMINE_URL and REDMINE_API_KEY environment variables are required. Configure them with: openclaw skills config epragma-redmine-issue set REDMINE_URL <your-redmine-url> and openclaw skills config epragma-redmine-issue set REDMINE_API_KEY <your-api-key>'); } return REDMINE_URL; } function getApiKey() { if (REDMINE_URL?.startsWith('http')) { return API_KEY; } if (API_KEY?.startsWith('http')) { return process.env.REDMINE_BASE_URL || ''; } return API_KEY; } export { getBaseUrl, getApiKey }; async function request(endpoint, options = {}) { const baseUrl = getBaseUrl(); const apiKey = getApiKey(); const url = `${baseUrl}${endpoint}`; const headers = { 'Content-Type': 'application/json', 'X-Redmine-API-Key': apiKey, ...options.headers, }; const response = await fetch(url, { ...options, headers, }); ``` ### Technical Analysis The destination check accepts any value beginning with `http`, which includes unencrypted `http://` endpoints. Every API request then attaches the Redmine credential in the `X-Redmine-API-Key` header. Issue descriptions, comments, time-entry information, and mutation request bodies may also be transmitted over the same unencrypted connection. The configuration logic additionally assigns multiple meanings to credential-related environment variables. `REDMINE_API_KEY` m ...[truncated 2526 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the configured endpoint using `new URL()` rather than relying on a prefix check. 2. Require the `https:` protocol in normal operation: ```js function getBaseUrl() { const rawUrl = process.env.REDMINE_URL; if (!rawUrl) { throw new Error('REDMINE_URL is required'); } const parsed = new URL(rawUrl); if (parsed.protocol !== 'https:') { throw new Error('REDMINE_URL must use HTTPS'); } parsed.username = ''; parsed.password = ''; return parsed.toString().replace(/\/$/, ''); } ``` 3. Give each environment variable exactly one purpose. Use only `REDMINE_URL` for the endpoint and `REDMINE_API_KEY` for the credential. 4. Remove the swapped-variable fallback involving `REDMINE_BASE_URL`. 5. Reject API-key values that resemble URLs and reject endpoint URLs containing embedded credentials. 6. If plaintext HTTP is required for local development, place it behind an explicit opt-in setting and restrict it to loopback hosts such as `127.0.0.1` or `localhost`. 7. Recommend a dedicated, least-privileged Redmine API account whose permissions are limited to the operations the user needs. 8. Rotate any API key that may previously have been transmitted over HTTP. 9. Update `SKILL.md` and `_meta.json` so the top-level description discloses that the Skill supports issue and time-entry mutation, rather than describing it only as a read operation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose says the skill reads Redmine issues, but the documented behavior includes creating issues, updating issues, adding comments, and creating time entries. This mismatch can mislead users and reviewers into granting or invoking the skill in contexts where they expect read-only behavior, enabling unintended modification of production project data.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The manifest presents the skill as only reading Redmine issues, while the command set includes state-changing operations. Security decisions are often made from manifest metadata first, so this inconsistency creates a real risk of overtrust and accidental authorization of a skill that can modify tickets, comments, and time records.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The imported command set includes write-capable operations such as updateIssue, createIssue, createTimeEntry, updateTimeEntry, deleteTimeEntry, and addComment, while the skill metadata describes a read-oriented capability. This mismatch can mislead users or orchestrators into granting or invoking the skill under the assumption that it is read-only, increasing the chance of unintended remote modifications on Redmine servers.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The update command performs authenticated remote modification of Redmine issues even though the declared skill purpose emphasizes reading and fetching. In agent environments, this kind of capability discrepancy can be abused or accidentally triggered, leading to unauthorized workflow changes, reassignment, status changes, or data corruption.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The create command opens new Redmine issues despite the skill being presented as a reader for existing issues. This broadens the operational authority of the skill beyond user expectations and can be exploited to create spam, misleading tickets, or unauthorized records in production project trackers.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill metadata and description present this as a read-oriented Redmine issue access skill, but the code includes write capabilities to create issues, update issues, and add comments. This scope mismatch is dangerous because users or higher-level agents may grant trust, credentials, or approval based on the stated read-only purpose while the implementation can perform state-changing actions against a Redmine server.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill claims issue-reading functionality, but the implementation can also create, modify, and delete time entries, which are unrelated destructive or state-changing operations beyond the advertised scope. In an agent setting, this hidden capability materially increases risk because an operator may unknowingly expose write-capable credentials to a tool they believe is limited to inspection.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill uses environment variables and network access to contact arbitrary Redmine servers, but the manifest does not declare any tool scope or allowed-tools restrictions. This weakens reviewability and policy enforcement because consumers may believe the skill is lower risk than it actually is, especially since it can act with configured credentials against external systems.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The top-level documentation frames the skill as a reader, but later sections document write operations. That inconsistency increases the chance that operators or automated systems will invoke the skill without appreciating that it can alter remote Redmine data using stored API credentials.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation for update, comment, create, and time-entry operations lacks a warning that these commands modify live Redmine data. In a skill that targets configurable external servers with API keys, omission of such warnings raises the likelihood of accidental or unauthorized changes across environments.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The update path executes the remote write immediately after parsing CLI options, with no user-facing warning, dry-run, or confirmation step. In an agent context, this increases the likelihood of accidental state changes from misunderstood prompts, malformed arguments, or indirect prompt injection steering the agent toward mutation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The comment command writes notes to remote issues, but that write behavior is not disclosed by the read-focused skill description. Hidden write capabilities are risky because agents or users may invoke the skill expecting inspection only, resulting in audit noise, accidental disclosures in comments, or unauthorized communication on tracked issues.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Adding a comment is a remote write operation, yet the tool provides no advance warning or confirmation before submitting user-supplied notes. That makes it easy for an agent to leak sensitive context, post incorrect information, or leave irreversible audit artifacts in Redmine.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Issue creation occurs directly once minimum arguments are present, without any pre-action confirmation. In practice this can lead to unauthorized ticket generation, spam, or misleading project records if the command is triggered by ambiguous user intent or manipulated agent input.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
Time-entry functionality extends the skill beyond issue reading into worklog access and mutation, including creation of time records. In many organizations, time entries affect billing, reporting, or compliance, so undisclosed support for these operations increases the risk of accidental or unauthorized business-impacting changes.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Time entry creation modifies remote records without any warning or confirmation, despite such changes potentially affecting labor reporting, billing, and audits. In agent-driven usage, silent mutation of time data is especially risky because it may not be immediately visible to the requester.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/lib/redmine.js:1