Back to skill

Security audit

Kaiten

Security checks for vulnerabilities and agentic risk

Overview

This Kaiten skill is coherent and not malicious, but it can modify or delete live project data with broad triggers, persisted context, and weak safeguards.

Install only if you trust the skill and will use a least-privilege Kaiten token. Check KAITEN_DOMAIN carefully, prefer a normal *.kaiten.ru tenant hostname, and ask the agent to confirm the exact card, board, and operation before any create, update, move, delete, membership, tag, or time-log action. Be cautious with ambiguous phrases like current board or same board because the skill reuses persisted last-used context.

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
scripts/kaiten.sh:5
Finding

Bearer Token Disclosure Through Unvalidated API Domain

Content
View full analysis
Remediation
View remediation
&2 exit 1 fi BASE="https://${domain}/api/latest" AUTH="Authorization: Bearer ${KAITEN_TOKEN}" ``` If custom Kaiten deployments must be supported, require an explicit allowlist rather than accepting an unrestricted environment-provided hostname. Protect `~/.openclaw/secrets/kaiten.env` with restrictive permissions and rotate the token if unauthorized modification or disclosure is suspected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/kaiten.sh:17
Finding

Python Code Injection Through Script Installation Path

Content
View full analysis
/dev/null || echo ""; } _update_state() { python3 -c " import json, sys f='$STATE_FILE' try: d=json.load(open(f)) except: d={} d[sys.argv[1]]=int(sys.argv[2]) if sys.argv[2].isdigit() else sys.argv[2] json.dump(d, open(f,'w'), indent=2) " "$1" "$2" } ``` ### Technical Analysis `STATE_FILE` is interpolated directly into Python source passed to `python3 -c`. It is not passed as data through `sys.argv` or an environment variable. If the absolute installation path contains a single quote followed by valid Python syntax, the generated `f='...'` statement can be terminated early and attacker-supplied Python can be executed. `_read_state` has the same unsafe interpolation pattern. Its `$1` state-key argument is also embedded directly into Python source, although current command dispatch uses `_read_state` only as an internal helper and does not expose a direct command path to it. Shell quoting does not prevent this issue because the injection occurs in the dynamically generated Python program after shell expansion. The installation path is therefore interpreted as executable Python syntax rather than exclusively as file-path data. ### Attack Path 1. An attacker controls or influences the directory under which the skill package is installed or extracted. 2. The attacker creates a directory name containing a single quote and a crafted Python expression or statement. 3. The user or agent runs a state-changing command such as `set-default-board`, `set-default-space`, `boards`, `columns`, `lanes`, or `create-card`. 4. `_update_state` calculate ...[truncated 1008 chars]
Remediation
View remediation
/dev/null || echo "" } _update_state() { python3 -c ' import json import sys path, key, value = sys.argv[1:4] try: with open(path, encoding="utf-8") as stream: data = json.load(stream) except (FileNotFoundError, json.JSONDecodeError): data = {} data[key] = int(value) if value.isdigit() else value with open(path, "w", encoding="utf-8") as stream: json.dump(data, stream, indent=2) ' "$STATE_FILE" "$1" "$2" } ``` Additional hardening should include: 1. Restricting state keys to a fixed allowlist. 2. Creating the state file with user-only permissions. 3. Avoiding broad `except:` handlers so unexpected security and filesystem errors are not silently ignored. 4. Writing updates atomically through a securely created temporary file followed by `os.replace`. 5. Testing execution from paths containing quotes, spaces, newlines, and Unicode characters. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (9)

Vague Triggers

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The README says the skill is automatically triggered when users mention broad everyday terms like Kaiten, tasks, boards, or cards. This creates an overbroad activation surface where ordinary conversation could invoke a skill capable of performing API-backed actions, including state changes and destructive operations, without sufficiently explicit user intent.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · README.md (reported line 23)May include surrounding context.

md
cp -r kaiten/ ~/.openclaw/workspace/skills/

# Set up credentials
mkdir -p ~/.openclaw/secrets
cat > ~/.openclaw/secrets/kaiten.env << 'ENVEOF'
KAITEN_TOKEN=your-bearer-token
KAITEN_DOMAIN=yourcompany.kaiten.ru

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 28)May include surrounding context.

KAITEN_TOKEN=your-bearer-token KAITEN_DOMAIN=yourcompany.kaiten.ru ENVEOF chmod 600 ~/.openclaw/secrets/kaiten.env

text

## State & Defaults

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README advertises destructive and state-changing commands such as delete-card, move-card, update-card, member changes, and time logging without warning that these modify live project data and may be irreversible. In an agent context, lack of cautionary guidance increases the chance of accidental misuse or unsafe delegation of high-impact operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill exposes multiple state-changing and destructive operations such as delete, move, update, and create without any explicit requirement for confirmation or warning before execution. In an agentic setting, this increases the risk of accidental or prompt-induced destructive actions against a live project-management system, especially because the skill is designed to act directly on production boards via authenticated API calls.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

The skill persists operational context across sessions using a state file and then reuses that context to select default or 'last used' boards, columns, and lanes. This can cause cross-request confusion or unintended actions in the wrong project context, particularly if a later user request is ambiguous and the agent silently applies stale state to a write operation.

Content

Scanner excerpt · SKILL.md (reported line 115)May include surrounding context.

  • After any operation on a space/board/column/lane → update last_* fields
  • When creating a card without explicit board → use default_board_id, fall back to last_board_id
  • When user says "текущая доска" / "та же доска" → use last_board_id
  • Read state before operations, write state after
bash
# Read state

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

This shell script requires a credential-bearing environment variable and sends it in HTTP Authorization headers on every API call. While the file has an internal comment noting the required variables, there is no user-facing warning in runtime output about transmitting credentials or remote data to the Kaiten API.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The script constructs the destination URL directly from the unvalidated KAITEN_DOMAIN environment variable and sends an Authorization bearer token on every request. If an attacker can influence that environment variable or trick a user into setting it to an attacker-controlled host, the script will exfiltrate the API token and potentially sensitive board/card data to that host over HTTPS.

Content

Scanner excerpt · scripts/kaiten.sh (reported line 9)May include surrounding context.

sh
BASE="https://${KAITEN_DOMAIN}/api/latest"
AUTH="Authorization: Bearer ${KAITEN_TOKEN}"

_get()  { curl -sf -H "$AUTH" "$BASE$1"; }
_post() { curl -sf -H "$AUTH" -H "Content-Type: application/json" -X POST -d "$2" "$BASE$1"; }
_patch(){ curl -sf -H "$AUTH" -H "Content-Type: application/json" -X PATCH -d "$2" "$BASE$1"; }
_del()  { curl -sf -H "$AUTH" -X DELETE "$BASE$1"; }

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The command name and inline comment say this operation will toggle the checklist item's checked state. However, the implementation unconditionally PATCHes {"checked":true}, which can only mark an item checked and cannot toggle it back to unchecked.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.