T09 · Insecure Skill Coding Practices
- Location
vikunja.sh:48- Finding
Bearer Token Can Be Transmitted over Unencrypted HTTP by the Main CLI
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Vikunja skill is a real task-management integration, but it includes high-impact credential, webhook, and file-transfer powers without enough safeguards.
Install only if you intend an agent to manage Vikunja beyond basic tasks, including attachments, webhooks, subscriptions, and API tokens. Use a least-privileged token, require HTTPS for VIKUNJA_URL, avoid running the smoke test against production, review every delete/token/webhook command before execution, and avoid uploading sensitive local files or downloading to sensitive paths.
vikunja.sh:48Bearer Token Can Be Transmitted over Unencrypted HTTP by the Main CLI
test-smoke.sh:13Smoke Test Harness Can Expose the Vikunja Bearer Token over HTTP
The declared purpose frames the skill as task/project management, but the documented behavior includes broader administrative and sensitive actions such as API token management, webhook administration, filesystem attachment handling, and subscription/notification changes. This mismatch can mislead users and automated policy systems, causing over-trust and accidental execution of higher-risk actions.
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).
delete)
[[ -n "$comment_id" ]] || die "--comment-id is required" 2
is_int "$comment_id" || die "--comment-id must be integer" 2
api_call DELETE "/tasks/${task_id}/comments/${comment_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown comments subcommand: ${sub}" 2 ;;
esac
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).
is_int "$task_id" || die "--task-id must be integer" 2
label_id="$(resolve_label_id "$label_id" "$label")"
[[ -n "$label_id" ]] || die "--label-id or --label is required" 2
api_call DELETE "/tasks/${task_id}/labels/${label_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown labels subcommand: ${sub}" 2 ;;
esac
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).
remove)
[[ -n "$user_id" ]] || die "--user-id is required" 2
is_int "$user_id" || die "--user-id must be integer" 2
api_call DELETE "/tasks/${task_id}/assignees/${user_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown assignees subcommand: ${sub}" 2 ;;
esac
While deletion itself is expected, deleting webhooks is part of the broader risky webhook-management capability, which is outside narrow task manipulation and affects external integrations. An agent with this function could disrupt monitoring/integration flows or cover tracks by removing existing callbacks.
delete)
[[ -n "$webhook_id" ]] || die "--webhook-id is required" 2
is_int "$webhook_id" || die "--webhook-id must be integer" 2
api_call DELETE "/projects/${project_id}/webhooks/${webhook_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown webhooks subcommand: ${sub}" 2 ;;
esac
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).
delete)
[[ -n "$attachment_id" ]] || die "--attachment-id is required" 2
is_int "$attachment_id" || die "--attachment-id must be integer" 2
api_call DELETE "/tasks/${task_id}/attachments/${attachment_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown attachments subcommand: ${sub}" 2 ;;
esac
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).
api_call PUT "/tasks/${task_id}/relations" "$(jq -n --argjson other "$other_task_id" --arg kind "$kind" '{other_task_id:$other,relation_kind:$kind}')" | jq '{task_id,other_task_id,relation_kind,created}'
;;
remove)
api_call DELETE "/tasks/${task_id}/relations/${kind}/${other_task_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown relations subcommand: ${sub}" 2 ;;
esac
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).
delete)
[[ -n "$id" ]] || die "--id is required" 2
is_int "$id" || die "--id must be integer" 2
api_call DELETE "/filters/${id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown filters subcommand: ${sub}" 2 ;;
esac
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).
api_call PUT "/subscriptions/${entity}/${entity_id}" | jq --arg e "$entity" --argjson id "$entity_id" '{message:(.message // "ok"),entity:$e,entity_id:$id}'
;;
unsubscribe)
api_call DELETE "/subscriptions/${entity}/${entity_id}" | jq --arg e "$entity" --argjson id "$entity_id" '{message:(.message // "ok"),entity:$e,entity_id:$id}'
;;
*) die "Unknown subscriptions subcommand: ${sub}" 2 ;;
esac
The skill can create and delete API tokens, giving it credential lifecycle capabilities beyond ordinary task/project operations. A compromised or prompt-influenced agent could mint long-lived tokens with broad permissions and use them for persistent unauthorized access even after the session ends.
Token deletion is part of the broader credential-management capability, which is sensitive and outside routine task operations. In an agent context, this can be abused to revoke legitimate credentials, cause denial of service for users/automation, or manipulate token inventory to hide malicious token creation.
delete)
[[ -n "$token_id" ]] || die "--token-id is required" 2
is_int "$token_id" || die "--token-id must be integer" 2
api_call DELETE "/tokens/${token_id}" | jq '{message:(.message // "ok")}'
;;
*) die "Unknown tokens subcommand: ${sub}" 2 ;;
esac
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
## Skill entrypoint
- Skill spec: `skills/vikunja/SKILL.md`
- CLI script: `skills/vikunja/scripts/vikunja.sh`
## Quick start
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
## Skill entrypoint
- Skill spec: `skills/vikunja/SKILL.md`
- CLI script: `skills/vikunja/scripts/vikunja.sh`
## Quick start
The skill exposes shell-driven operational capabilities but does not declare any tool scope or allowed-tools restrictions. In an agent environment, this weakens least-privilege controls and can let a seemingly simple documentation skill invoke broader command execution than users or orchestrators expect.
The setup instructions normalize exporting a long-lived API token and using it for remote operations, but they provide no warning about credential sensitivity, storage risk, or transmission to the Vikunja server. This can lead to accidental token exposure in shell history, logs, screenshots, or insecure environments.
The documentation prominently includes mutation and deletion commands for remote Vikunja resources without warning that these actions change or permanently remove server-side data. In agent-assisted workflows, omission of these cautions increases the chance of destructive actions being run unintentionally or without adequate confirmation.
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.
{baseDir}/scripts/vikunja.sh health
{baseDir}/scripts/vikunja.sh list --project "Inbox" --limit 25
{baseDir}/scripts/vikunja.sh create --project "Inbox" --title "Call vendor" --due "2026-03-15" --priority 4
{baseDir}/scripts/vikunja.sh update --id 123 --title "Updated title" --priority 5 --reminder "2026-03-14"
{baseDir}/scripts/vikunja.sh move --id 123 --project "Ops" --view "Kanban" --bucket "In Progress"
{baseDir}/scripts/vikunja.sh complete --id 123
This smoke test makes authenticated network calls that enumerate, create, and modify remote Vikunja projects and tasks using a bearer token, but it provides no explicit warning, confirmation, or safe test-environment guardrail before performing those side effects. In a production-oriented skill, this is dangerous because users may run the script against a live instance and unintentionally alter real data.
The script transmits an Authorization: Bearer token in an outbound curl request to whatever endpoint is configured in VIKUNJA_URL, and then performs a remote project-creation operation. While this is expected functionality for an integration test, it becomes a security risk if the environment variable points to an untrusted, mistyped, or production endpoint, because sensitive credentials and write actions are sent without additional validation.
local id
id="$(project_id_by_title "$title")"
if [[ -z "$id" ]]; then
id="$(curl -sS -X PUT "$VIKUNJA_URL/api/v1/projects" -H "Authorization: Bearer $VIKUNJA_TOKEN" -H 'Content-Type: application/json' -d "{\"title\":\"$title\"}" | jq -r '.id')"
fi
echo "$id"
}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
curl_rc=0
if [[ -n "$data" ]]; then
code="$(curl -sS -o "$tmp" -w "%{http_code}" -X "$method" "$url" \
-H "Authorization: Bearer ${VIKUNJA_TOKEN}" \
-H "Content-Type: application/json" \
--connect-timeout 10 --max-time 30 \
The skill exposes webhook creation and deletion, which extends it from task management into outbound network integration. In an agent setting, this can be abused to register attacker-controlled callback URLs and exfiltrate task contents, metadata, or future events from the Vikunja instance.
The upload command sends an arbitrary local file to the remote Vikunja server without any built-in disclosure or friction beyond the flag itself. In an agent context, this materially increases exfiltration risk because a model can be induced to send local secrets or sensitive documents off-host.
Attachment download writes server-controlled content to any user-supplied output path with no path restriction or safety prompt. In an agent workflow, this can overwrite sensitive local files, drop content into startup/config locations, or stage follow-on compromise on the host running the skill.
No suspicious patterns detected.