Back to skill

Security audit

YouTrack Project Management

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent YouTrack integration, but it handles a permanent API token and sensitive project data with weak destination checks and under-disclosed invoice data exposure.

Review this before installing. Use only a least-privilege YouTrack token, store it in a protected environment variable or secret manager, avoid the --token argument, and verify the URL is your HTTPS YouTrack host before running. Treat generated invoices as sensitive because they may include internal issue descriptions, author names, and work-log details; redact before sharing externally.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/youtrack_api.py:26
Finding
Permanent API Token Can Be Sent to an Arbitrary or Plaintext Origin<![CDATA[ ## Vulnerability Details **File Location**: `scripts/youtrack_api.py`, lines 26-43 and 50-64 **Vulnerability Type**: Unvalidated credential destination and insecure transport **Risk Level**: High ### Vulnerable Code ```python def __init__(self, base_url: str, token: Optional[str] = None): """ Initialize YouTrack API client. Args: base_url: Your YouTrack instance URL (e.g., https://sl.youtrack.cloud) token: Permanent API token (or set YOUTRACK_TOKEN env var) """ # Normalize base URL self.base_url = base_url.rstrip('/') self.token = token or os.environ.get('YOUTRACK_TOKEN') if not self.token: raise ValueError( "YouTrack token required. Set YOUTRACK_TOKEN env var or pass as argument." ) # Set up headers with bearer token auth self.headers = { 'Authorization': f'Bearer {self.token}', 'Accept': 'application/json', 'Content-Type': 'application/json' } ``` ```python def _make_request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]: """ Make an authenticated API request. Args: method: HTTP method (GET, POST, PUT, DELETE) endpoint: API endpoint (e.g., '/api/issues') data: Request body for POST/PUT Returns: Parsed JSON response """ url = urljoin(self.base_url, endpoint) req_data = None if data is not None: req_data = json.dumps(data).encode('utf-8') req = urllib.request.Request( url, data=req_data, headers=self.headers, method=method ) ``` ### Technical Analysis The caller supplies `base_url`, but the client does not validate its scheme, hostname, port, or relationship to an approved YouTrack instance. Every request generated by the client automatically receives the permanent bearer token through the shared `Authorization` header. If an `http://` URL is supplied, the token and associated request d ...[truncated 1797 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the supplied URL with `urllib.parse.urlsplit` and reject every scheme except `https`. 2. Reject URLs containing user information, fragments, unexpected ports, or malformed hostnames. 3. Support an administrator-configured allowlist of approved YouTrack hostnames. 4. Normalize the hostname before comparing it with the allowlist. 5. If local development requires HTTP, permit it only through an explicit opt-in flag and restrict it to loopback addresses. 6. Display or log the normalized credential destination without logging the token. 7. Require explicit user confirmation before sending credentials to a previously unknown host. 8. Use a narrowly scoped token where YouTrack supports applicable permission restrictions. 9. Rotate the token immediately if it may have been sent to an untrusted endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:71
Finding
Command-Line Token Option Can Expose Permanent Credentials<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 71-74; `scripts/youtrack_api.py`, lines 198-204; `scripts/invoice_generator.py`, lines 188-196 **Vulnerability Type**: Sensitive credential exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code The documentation provides a token-bearing command-line example: ```bash python3 scripts/youtrack_api.py --url https://your-instance.youtrack.cloud \ --token YOUR_TOKEN \ --list-projects ``` The API client accepts the token as an ordinary command-line argument: ```python parser = argparse.ArgumentParser(description='YouTrack API Client') parser.add_argument('--url', required=True, help='YouTrack instance URL') parser.add_argument('--token', help='API token (or set YOUTRACK_TOKEN env var)') parser.add_argument('--list-projects', action='store_true', help='List all projects') parser.add_argument('--list-issues', help='List issues (optional query)') parser.add_argument('--get-issue', help='Get specific issue ID') parser.add_argument('--get-articles', action='store_true', help='List articles') args = parser.parse_args() ``` The invoice generator exposes the same option: ```python parser = argparse.ArgumentParser(description='YouTrack Invoice Generator') parser.add_argument('--url', required=True, help='YouTrack instance URL') parser.add_argument('--token', help='API token (or set YOUTRACK_TOKEN env var)') parser.add_argument('--project', required=True, help='Project ID to generate invoice for') parser.add_argument('--from-date', help='Start date (YYYY-MM-DD)') parser.add_argument('--month', help='Month label (e.g., "January 2026")') parser.add_argument('--rate', type=float, default=100.0, help='Hourly rate (default: 100)') parser.add_argument('--format', choices=['text', 'json'], default='text', help='Output format') args = parser.parse_args() ``` ### Technical Analysis Command-line arguments are not an appropriate channel for permanent credenti ...[truncated 1515 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove token-bearing command examples from `SKILL.md`. 2. Prefer a protected credential provider or `YOUTRACK_TOKEN` over process arguments. 3. Consider removing `--token` from both CLI programs. 4. If interactive entry is required, use `getpass.getpass()` so the token is not echoed. 5. If file-based authentication is supported, require restrictive file permissions and avoid printing the file contents. 6. If backward compatibility requires `--token`, emit a prominent warning that the value may be exposed through history and process listings. 7. Ensure CI/CD systems inject the token through a secret manager and mask it in logs. 8. Document token rotation and revocation procedures. ]]>

T05 · Unauthorized Access and Privilege Escalation

Note
Location
scripts/invoice_generator.py:45
Finding
Invoice Generation Retrieves and Emits More Project Data Than Required<![CDATA[ ## Vulnerability Details **File Location**: `scripts/youtrack_api.py`, lines 92-116 and 138-141; `scripts/invoice_generator.py`, lines 45-87 and 173-181 **Vulnerability Type**: Excessive data retrieval and disclosure beyond billing requirements **Risk Level**: Low ### Vulnerable Code The default issue query asks for descriptions and custom fields: ```python def get_issues(self, query: Optional[str] = None, fields: str = 'id,summary,description,created,updated,project(id,name),customFields(name,value)') -> List[Dict]: """ Get issues, optionally filtered by a query. Args: query: YouTrack query language (e.g., 'project: MyProject') fields: Comma-separated list of fields to return Returns: List of issues """ params = {'fields': fields} if query: params['query'] = query # Build query string query_string = '&'.join(f'{k}={urllib.parse.quote(str(v))}' for k, v in params.items()) endpoint = f'/api/issues?{query_string}' result = self._make_request('GET', endpoint) return result if isinstance(result, list) else [] def get_issue(self, issue_id: str) -> Dict: """Get a specific issue by ID.""" return self._make_request('GET', f'/api/issues/{issue_id}') ``` Work-item retrieval requests author names and work-item text even though cost calculation only uses duration: ```python def get_work_items(self, issue_id: str) -> List[Dict]: """Get all work items (time entries) for an issue.""" result = self._make_request('GET', f'/api/issues/{issue_id}/timeTracking/workItems?fields=id,date,duration(minutes),author(name),text') # Convert date from milliseconds to ISO format for wi in result: if 'date' in wi and wi['date']: wi['date'] = datetime.fromtimestamp(wi['date'] / 1000).isoformat() return result if isinstance(result, list) else [] ``` The invoice workflow retains those fields: ```python issues = self.api.get_issues(query=query) proj ...[truncated 3646 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define an invoice-specific issue query requesting only necessary fields, such as issue ID, summary, and project name. 2. Request only work-item date and duration by default. 3. Remove `text` and `author(name)` from work-item queries unless explicitly requested. 4. Add a restrictive `fields` parameter to `get_issue()` or avoid the additional full issue request entirely. 5. Do not retain raw API work-item objects in invoice data. 6. Construct a dedicated invoice item model containing only approved billing fields. 7. Exclude descriptions, author names, custom fields, and raw work-log text from JSON output by default. 8. Add explicit options such as `--include-descriptions` or `--include-authors` if those fields are genuinely required. 9. Warn users that generated invoices may contain project information before writing or transmitting them. 10. Add tests that verify default invoice output cannot contain work-item text or unrelated custom fields. ]]>
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 (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill claims invoice-generation capabilities, including billing logic and client-facing export workflows, but the analyzed content provides only documentation and no implementation evidence for those functions. This mismatch is dangerous because users may authorize sensitive project/time-tracking access under false assumptions about what the skill does, reducing auditability and increasing the chance of unsafe substitute behavior or later hidden implementation drift.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation explicitly instructs users to use a permanent API token for authentication but does not include any warning about treating the token as a secret, avoiding logging or embedding it in files, or preferring least-privilege and rotation practices. In a skill that interacts with projects, issues, work items, and knowledge base content, a leaked long-lived bearer token could enable unauthorized reading and modification of sensitive operational data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill documents use of environment variables for a permanent API token and network access to a remote YouTrack instance, but the manifest does not declare any tool scope or permissions. This creates a trust and containment gap: an agent or reviewer cannot reliably infer that the skill will access secrets and external services before use.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The documentation instructs users to generate invoice text from time-tracking data and save it for client distribution, but it does not warn that exported artifacts may contain sensitive employee, project, or work-log details. In this context, the skill processes operational and billing data, so omission of privacy guidance increases the risk of accidental data leakage.

Static analysis

No suspicious patterns detected.