T09 · Insecure Skill Coding Practices
Warning
- Location
- SKILL.md:19
- Finding
- Vikunja credentials and long-lived bearer tokens transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:19-23`, `SKILL.md:48-134`, and `SKILL.md:142-160` **Vulnerability Type**: Plaintext transmission of sensitive authentication data **Risk Level**: Medium ### Vulnerable Code The login example transmits a username and password to an unencrypted HTTP endpoint: ```bash RESP=$(curl -s -X POST http://localhost:3456/api/v1/login \ -H 'Content-Type: application/json' \ -d '{"username":"your-user","password":"your-pass"}') TOKEN=$(echo "$RESP" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) echo "$TOKEN" ``` The Python template similarly uses plaintext HTTP while attaching the bearer token to requests: ```python import requests, os BASE = "http://localhost:3456/api/v1" TOKEN_FILE = os.path.join(os.getenv("AGENT_WORKSPACE", "."), "config", ".vikunja-token") def get_token(): if os.getenv("VIKUNJA_TOKEN"): return os.getenv("VIKUNJA_TOKEN") with open(TOKEN_FILE) as f: return f.read().strip() def headers(): return {"Authorization": f"Bearer {get_token()}", "Content-Type": "application/json"} def create_task(project_id, title, **kw): return requests.put(f"{BASE}/projects/{project_id}/tasks", json={"title": title, **kw}, headers=headers()).json() def update_task(task_id, **kw): return requests.post(f"{BASE}/tasks/{task_id}", json=kw, headers=headers()).json() def search_tasks(q): return requests.get(f"{BASE}/tasks", params={"s": q}, headers=headers()).json() ``` The other documented project, task, comment, label, assignee, and information requests also send the same bearer token through `http://localhost:3456`. ### Technical Analysis HTTP provides no transport encryption or server authentication. The login request therefore exposes the Vikunja username and password in plaintext at the transport layer. All authenticated API examples subsequently expose the bearer token in the same manner. The endpoint is restricted to loopback in the s ...[truncated 2194 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Configure Vikunja to use HTTPS and replace the embedded HTTP base URL with a configurable HTTPS endpoint. 2. Require certificate verification. Do not disable TLS validation in either `curl` or Python `requests`. 3. For a strictly local deployment, terminate TLS directly in Vikunja or through a trusted local reverse proxy with a certificate trusted by the agent environment. 4. Validate the configured endpoint and reject plaintext HTTP unless the user explicitly enables a documented development-only exception after understanding the risk. 5. Prefer short-lived, least-privileged, per-agent API tokens over reusable account passwords or indefinite tokens. 6. Document and implement explicit revocation of a leaked token. Logging in to obtain a replacement must not be presented as sufficient unless the old token is invalidated. 7. Avoid printing tokens to standard output. Replace `echo "$TOKEN"` with a direct, permission-restricted storage procedure where possible. 8. Retain the existing mode-`600` token-file requirement and metadata-only logging rule, as these are appropriate protections for credentials at rest and in logs. ]]>
