Back to skill

Security audit

Yandex Tracker CLI

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Yandex Tracker CLI, but it needs review because it can delete Tracker data without confirmation and its attachment path protections can be bypassed with symlinks.

Review this before installing if the OAuth token can modify important Tracker data. Use the least-privileged token available, keep any ~/.yandex-tracker-env file private, manually confirm issue/comment/checklist IDs before destructive commands, and use a dedicated attachment directory without symlinks or sensitive files.

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

Error
Location
yandex-tracker.sh:102
Finding
Attachment directory restriction can be bypassed through symbolic links<![CDATA[ ## Vulnerability Details **File Location**: `yandex-tracker.sh:102-151`, `yandex-tracker.sh:256-281` **Vulnerability Type**: Symbolic-link path traversal and sandbox bypass **Risk Level**: High ### Vulnerable Code ```bash _resolve_absolute() { local path="$1" [[ -z "$path" ]] && return 1 [[ "$path" == ~* ]] && path="${HOME}${path:1}" if [[ "$path" != /* ]]; then [[ -z "$PWD" ]] && return 1 path="$PWD/$path" fi local result="/" local part while [[ -n "$path" ]]; do path="${path#/}" part="${path%%/*}" path="${path#$part}" path="${path#/}" [[ -z "$part" || "$part" == . ]] && continue if [[ "$part" == .. ]]; then result=$(dirname "$result") continue fi result="${result%/}/$part" done [[ -z "$result" ]] && result="/" echo "$result" } _get_attachment_base() { if [[ -n "${YANDEX_TRACKER_ATTACHMENTS_DIR}" ]]; then local expanded="${YANDEX_TRACKER_ATTACHMENTS_DIR}" [[ "$expanded" == ~* ]] && expanded="${HOME}${expanded:1}" if [[ "$expanded" != /* ]]; then expanded="$PWD/$expanded" fi _resolve_absolute "$expanded" else _resolve_absolute "$PWD" fi } _path_under_base() { local resolved="$1" local base="$2" [[ -z "$resolved" || -z "$base" ]] && return 1 [[ "$resolved" == "$base" ]] && return 0 [[ "$resolved" == "$base/"* ]] && return 0 return 1 } _ensure_attachment_path_allowed() { local kind="$1" # "download" or "upload" local path="$2" local resolved resolved=$(_resolve_absolute "$path") || { echo "Error: invalid path: $path" >&2; return 1; } local base base=$(_get_attachment_base) || { echo "Error: could not determine allowed attachment directory" >&2; return 1; } if ! _path_under_base "$resolved" "$base"; then echo "Error: attachment path must be under the allowed directory (current directory or YANDEX_TRACKER_ATTACHMENTS_DIR)." >&2 return 1 fi return 0 } ``` ```bash attachment_download() { ensure_attachme ...[truncated 3800 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Canonicalize both the configured base directory and upload source with `realpath` or an equivalent facility that resolves symbolic links. 2. Compare canonical paths, including a path-separator boundary, rather than comparing lexically normalized strings. 3. Reject upload source files that are symbolic links. Where practical, also reject paths containing symbolic-link parent components. 4. Recheck the canonical path immediately before use to reduce time-of-check/time-of-use exposure. 5. For downloads, do not pass a user-selected existing path directly to `curl -o`. Create a temporary regular file securely inside the canonical approved directory with `mktemp`, download into it, and move it to a verified destination. 6. Reject an existing destination if it is a symbolic link. Verify that the destination parent directory resolves beneath the approved base. 7. Set restrictive permissions on created directories and files, such as `0700` for private attachment directories and an appropriate restrictive `umask`. 8. Add regression tests covering: - A direct file symlink inside the approved directory. - A symlinked parent directory. - An upload path that resolves outside the base. - A download destination symlink. - Relative paths containing `..`. - Replacement of a checked path between validation and use. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
yandex-tracker.sh:173
Finding
User-controlled arguments are interpolated into JSON without escaping<![CDATA[ ## Vulnerability Details **File Location**: `yandex-tracker.sh:173-180`, `yandex-tracker.sh:213-217`, `yandex-tracker.sh:241-248`, `yandex-tracker.sh:290-294` **Vulnerability Type**: JSON injection and malformed API request construction **Risk Level**: Medium ### Vulnerable Code ```bash issue_create() { local queue="$1" local summary="$2" local extra extra=$(cat) if [[ -z "$extra" ]]; then body="{\"queue\":\"$queue\",\"summary\":\"$summary\",\"tags\":[\"yandex-tracker-cli\"]}" else ``` ```bash issue_comment() { local id="$1" local text="$2" curl -sS -X POST -H "$AUTH" -H "$ORG" -H "Content-Type: application/json" \ -d "{\"text\":\"$text\"}" "$BASE/issues/$(urlencode "$id")/comments" } ``` ```bash issue_worklog() { local id="$1" local duration="$2" local comment="${3:-}" local body="{\"duration\":\"$duration\"}" if [[ -n "$comment" ]]; then body="{\"duration\":\"$duration\",\"comment\":\"$comment\"}" fi ``` ```bash issue_comment_edit() { local issue_id="$1" local comment_id="$2" local new_text="$3" curl -sS -X POST -H "$AUTH" -H "$ORG" -H "Content-Type: application/json" \ -d "{\"text\":\"$new_text\"}" "$BASE/issues/$(urlencode "$issue_id")/comments/$(urlencode "$comment_id")" } ``` ### Technical Analysis The affected functions construct JSON by inserting user-controlled shell arguments directly between JSON quotation marks. JSON metacharacters are not escaped. Values containing quotation marks, backslashes, newlines, tabs, or other control characters can produce malformed JSON. Crafted values can also terminate the intended string and introduce additional JSON properties. Whether an injected property changes application state depends on the schema and duplicate-key behavior of the relevant Yandex Tracker endpoint, but malformed-request denial and corruption of the intended request semantics are directly possible. This is not shell-command injection because the values remain inside quoted s ...[truncated 1462 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Construct every JSON request with `jq` rather than shell string interpolation. For example: ```bash body=$(jq -n \ --arg queue "$queue" \ --arg summary "$summary" \ '{queue: $queue, summary: $summary, tags: ["yandex-tracker-cli"]}') ``` Comments should be serialized as follows: ```bash body=$(jq -n --arg text "$text" '{text: $text}') curl -sS -X POST -H "$AUTH" -H "$ORG" \ -H "Content-Type: application/json" \ --data-binary "$body" \ "$BASE/issues/$(urlencode "$id")/comments" ``` Apply the same pattern to edited comments, worklog durations, worklog comments, and every other request body assembled from arguments. Additional hardening should include: 1. Validate stdin payloads with `jq -e` before transmitting them. 2. Enforce expected JSON types and reject non-object payloads where objects are required. 3. Prefer `printf '%s'` or direct file input over `echo` when passing arbitrary JSON between commands. 4. Add tests containing quotation marks, backslashes, Unicode, embedded newlines, tabs, and attempted additional JSON properties. 5. Return a clear local validation error rather than sending malformed JSON to the remote API. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The README instructs users to store an OAuth token and Org ID in environment variables or a plaintext file under the home directory, but gives no guidance on protecting those credentials. In a CLI context, this can lead to accidental disclosure through shell history, weak file permissions, backups, process inspection, or shared workstation access, enabling unauthorized API access to Tracker.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This is a markdown file, so SQP-2 applies to missing safety warnings in the skill description. The command list includes `issue-delete` and `issue-comment-delete`, but the README provides no caution that these operations modify or remove remote Tracker data and may be irreversible.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill clearly instructs use of shell-executable artifacts and command execution, but it does not declare any explicit tool scope or allowed-tools policy. In agent environments, this increases the chance that the skill will be granted overly broad shell access by default, making misuse or prompt-driven command execution harder to constrain.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file's user-facing instructions, command explanations, and safety guidance are presented only in Russian. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicit and justified, which is not stated here.

Session Persistence

Medium
Category
Rogue Agent
Content
1. Скопируйте скрипт в директорию в PATH:
```bash
mkdir -p ~/bin
cp yandex-tracker.sh ~/bin/yandex-tracker
chmod +x ~/bin/yandex-tracker
```
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.

Session Persistence

Medium
Category
Rogue Agent
Content
1. Cкoпиpyйтe cкpипт в диpeктopию в PATH:
```bash
mkdir -p ~/bin
cp yandex-tracker.sh ~/bin/yandex-tracker
chmod +x ~/bin/yandex-tracker
```
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
TOKEN='y0__...'
ORG_ID='1234...'
```
Предпочтительно задавать учётные данные переменными окружения. Если используете файл — установите права `chmod 600 ~/.yandex-tracker-env`.

3. Убедитесь, что `jq` установлен:
```bash
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
3. Убедитесь, что `jq` установлен:
```bash
sudo apt install jq   # Ubuntu/Debian
# или
brew install jq       # macOS
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The documentation claims attachment upload/download paths are restricted to a safe directory, but this file contains only policy text and no enforcement. If the underlying script does not actually canonicalize and validate paths, an agent or user could read from or write to arbitrary local files, including secrets and sensitive system locations.

External Transmission

Medium
Category
Data Exfiltration
Content
exit 1
fi

BASE="https://api.tracker.yandex.net/v2"
BASE_V3="https://api.tracker.yandex.net/v3"
AUTH="Authorization: OAuth $TOKEN"
ORG="X-Org-Id: $ORG_ID"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
exit 1
fi

BASE="https://api.tracker.yandex.net/v2"
BASE_V3="https://api.tracker.yandex.net/v3"
AUTH="Authorization: OAuth $TOKEN"
ORG="X-Org-Id: $ORG_ID"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
.tags = ((.tags // [] | map(tostring)) + ["yandex-tracker-cli"] | unique)
    ')
  fi
  curl -sS -X POST -H "$AUTH" -H "$ORG" -H "Content-Type: application/json" \
    -d "$body" "$BASE/issues"
}
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
payload=$(echo "$payload" | jq '
    .tags = ((.tags // [] | map(tostring)) + ["yandex-tracker-cli"] | unique)
  ')
  curl -sS -X PATCH -H "$AUTH" -H "$ORG" -H "Content-Type: application/json" \
    -d "$payload" "$BASE/issues/$(urlencode "$id")"
}
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The CLI exposes issue deletion as a single-step command with no confirmation prompt, dry-run mode, or safety interlock. In an agent or automation context, a malformed prompt, typo, or unintended invocation can permanently remove issue data with little friction.

External Transmission

Medium
Category
Data Exfiltration
Content
else
    form_data=""
  fi
  curl -sS -X POST -H "$AUTH" -H "$ORG" \
    -F "file=@$filepath;filename=$file_name" \
    ${form_data:+-F "$form_data"} \
    "$BASE/issues/$(urlencode "$issue_id")/attachments"
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
Comment deletion is irreversible content removal and currently happens without any user-facing warning or confirmation. In interactive or agent-driven use, this increases the risk of accidental deletion of audit-relevant discussion or instructions.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest describes a CLI for Yandex Tracker focused on queues, issues, comments, worklogs, attachments, and YQL. The code also implements sprint, project, users, statuses, resolutions, issue types, checklist, and export-report operations, which materially broaden the skill beyond the stated scope rather than serving as an obvious implementation detail of the listed features.

External Transmission

Medium
Category
Data Exfiltration
Content
perPage="?perPage=50&page=$pg"
    fi
  fi
  curl -sS -X POST -H "$AUTH" -H "X-Org-ID: $ORG_ID" -H "Content-Type: application/json" \
    -d "$payload" "$BASE_V3/issues/_search${perPage}"
}
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
if [[ -z "$text" ]]; then
    text="(item)"
  fi
  curl -sS -X PATCH -H "$AUTH" -H "$ORG" -H "Content-Type: application/json" \
    -d "$(jq -n --arg t "$text" --argjson ch true '{text: $t, checked: $ch}')" \
    "$BASE_V3/issues/$(urlencode "$issue_id")/checklistItems/$(urlencode "$item_id")"
}
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
Checklist item deletion is a destructive action that proceeds immediately with no confirmation barrier. While lower impact than deleting issues, it can still silently remove task-tracking data and mislead teams about completion state.

Natural-Language Policy Violations

Low
Confidence
70% confidence
Finding
SQP-3 applies to all file types and includes language or locale policy violations. The entire user-facing README is in Russian with no indication of optional language support, opt-in, or a documented region-specific justification.

Static analysis

No suspicious patterns detected.