Back to skill

Security audit

Kalodata-tiktok e‑commerce data query

Security checks for vulnerabilities and agentic risk

Overview

This TikTok Shop analytics skill is coherent, but it needs review because it can store a KaloData API key and send it to a user-configurable API endpoint.

Install only if you trust the publisher and need KaloData-backed TikTok Shop analytics. Keep the API base URL at the production KaloData endpoint, avoid setting KALODATA_BASE_URL unless you fully trust the destination, prefer environment-based secrets where possible, and watch for credit-consuming multi-call analysis workflows.

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
scripts/kalodata/config.py:54
Finding

API Key Can Be Exfiltrated Through an Arbitrary or Insecure API Base URL

Content
View full analysis

Vulnerability Details

File Location: scripts/kalodata/config.py:54-64; scripts/kalodata/api.py:35-42, 91-100; scripts/kalodata/commands/meta.py:32-36, 68-72
Vulnerability Type: Unrestricted credential destination and insecure transport configuration
Risk Level: High

Vulnerable Code

scripts/kalodata/config.py:54-64:

python
def pick(key: str, fallback: str | None = None) -> str | None:
    env = os.environ.get(ENV_KEYS[key])
    if env:
        return env
    val = data.get(key)
    if val is not None:
        return str(val)
    return fallback

return Config(
    api_key=pick("api_key"),
    base_url=pick("base_url", DEFAULT_BASE_URL) or DEFAULT_BASE_URL,

scripts/kalodata/api.py:35-42:

python
def _headers(cfg: Config, extra: dict | None) -> dict:
    h = {
        "Content-Type": "application/json;charset=UTF-8",
        "secret-key": cfg.api_key,
        "source-type": "SKILL",
    }
    if extra:
        h.update(extra)
    return h

scripts/kalodata/api.py:91-100:

python
"""Call base_url+path (JSON body for POST, query params for GET); return the envelope's `data`."""
_require_auth(cfg)
url = cfg.base_url.rstrip("/") + path
headers = _headers(cfg, extra_headers)
if method == "GET":
    if body:
        url += "?" + urllib.parse.urlencode(body)
    payload = None
else:
    payload = json.dumps(body).encode("utf-8")

scripts/kalodata/commands/meta.py:32-36,68-72:

python
updates = {
    "api_key": opts.get("key"),
    "base_url": opts.get("base_url"),
    "region": opts.get("region"),
    "language": opts.get("language"),
    "currency": opts.get("currency"),
}
python
flags=[
    Flag("--key", "KaloData API token (secret-key header)", metavar="KEY"),
    Flag("--base-url", "API base URL (default production)", metavar="URL"),
    Flag("--region", "default region", metavar="REGIO
...[truncated 2012 chars]
Remediation
View remediation

Remediation Suggestions

  1. Default to the fixed production endpoint and do not expose a configurable base URL unless it is operationally necessary.
  2. Enforce HTTPS and reject HTTP, non-network schemes, embedded credentials, fragments, unexpected ports, and malformed URLs.
  3. Allowlist trusted hosts, preferably only www.kalodata.com, and validate the normalized hostname rather than using suffix matching.
  4. If development endpoints are required, require a separate explicit opt-in and separate development credentials.
  5. Implement a redirect handler that rejects cross-origin redirects. Never forward secret-key to a host or scheme different from the validated original destination.
  6. Validate environment-derived and file-derived configuration using the same policy as command-line configuration.
  7. Consider refusing to send production credentials whenever the endpoint differs from the production origin.
  8. Add tests covering HTTP URLs, attacker-controlled domains, embedded credentials, deceptive subdomains, alternate ports, and cross-origin redirects.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/kalodata/config.py:76
Finding

API Credential File Is Written Non-Atomically Before Restrictive Permissions Are Applied

Content
View full analysis

Vulnerability Details

File Location: scripts/kalodata/config.py:71-82
Vulnerability Type: Insecure secret-file creation and unsafe file replacement
Risk Level: Medium

Vulnerable Code

python
def save(updates: dict) -> Path:
    data = _read_file()
    data.update({k: v for k, v in updates.items() if v is not None})
    path = config_path()
    path.parent.mkdir(parents=True, exist_ok=True)
    lines = []
    for k, v in data.items():
        escaped = str(v).replace("\\", "\\\\").replace('"', '\\"')
        lines.append(f'{k} = "{escaped}"')
    path.write_text("\n".join(lines) + "\n", encoding="utf-8")
    os.chmod(path, 0o600)
    return path

Technical Analysis

The configuration may contain the API key, but Path.write_text() creates or truncates the destination before os.chmod() applies mode 0600. For a newly created file, its initial permissions depend on the process umask. Under an overly permissive umask, other local users may temporarily be able to read the credential between creation and the subsequent permission change.

The write is also not atomic. Readers may observe partially written configuration content, and an interruption can leave a truncated file. Moreover, the predictable destination is opened without protections against symbolic links or file-replacement races. In a context where another local actor can manipulate the configured directory or destination, the write may follow an attacker-created link.

Attack Path

  1. The user runs kalo config set --key to save an API credential.
  2. The process uses a permissive umask, or an attacker can manipulate or monitor the selected configuration directory.
  3. path.write_text() creates or truncates the predictable config.toml destination before restrictive permissions are applied.
  4. A local attacker reads the file during the permission window, or prepares a symbolic link or replacement race where direc ...[truncated 723 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create a temporary file in the same directory with mode 0600 at creation time, rather than changing permissions after writing.
  2. Use low-level file creation flags such as O_CREAT, O_EXCL, and O_WRONLY; use O_NOFOLLOW where supported to reject symbolic links.
  3. Write the complete content, flush it, call fsync(), and atomically replace the destination with os.replace().
  4. Verify that the destination is a regular file owned by the expected user before replacing or updating it.
  5. Ensure the configuration directory itself has restrictive permissions, such as 0700, and reject unsafe ownership or writable-by-others conditions.
  6. Preserve mode 0600 after atomic replacement and consider synchronizing the parent directory for durability.
  7. Add tests using permissive umasks, pre-existing symbolic links, interrupted writes, and concurrent readers.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises substantial functionality for querying TikTok Shop/KaloData analytics, but the provided code contains only __version__ = "0.1.0". There is no evidence in this chunk of any CLI, network access, data retrieval, analytics processing, or TikTok/KaloData integration. This is a material description-versus-behavior mismatch because the actual code shown does not implement the claimed primary purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose focuses on querying TikTok Shop/KaloData analytics data. The supplied code does not perform any analytics queries, ranking lookups, revenue retrieval, or TikTok Shop research actions. Its primary function is configuration management for the CLI: showing current settings and saving credentials/defaults locally. While this may support the broader analytics tool, this specific code chunk's behavior is materially different from the declared purpose, so it should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description claims the skill queries TikTok Shop e-commerce analytics through the kalo CLI and supports research on products, shops, creators, videos, livestreams, and revenue trends. However, the provided code only defines helper functions (scalar, tabular, kv, _encode_list) for serializing Python data structures into a custom text notation. It does not call external services, invoke a CLI, access KaloData, process TikTok Shop entities, or implement analytics features. While this module could be a supporting utility within a larger analytics skill, the supplied chunk itself does not match the declared primary purpose.

Content

No source excerpt is available for this finding.

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
97% confidence
Finding

The instruction 'Do not keep asking, and do not refuse to answer' is an anti-refusal pattern that pressures the agent to respond even when required identifiers or sufficient grounding data are missing. In practice, this can suppress safe abstention and encourage fabricated, weakly grounded, or policy-inconsistent answers, especially when the user insists on unsupported claims or missing-account analysis.

Content

Scanner excerpt · references/playbooks.md (reported line 42)May include surrounding context.

md
**Triggers**: "analyze @creator", "what's this account's growth/selling strategy", "are they a good fit" — anything focused on a **single creator**. To find candidates use playbook 4.

**Precondition**: you need a creator id, an @handle, or a name + region. Ask once if you have none; if the user still doesn't provide one, give generic advice prefixed with "⚠️ No account data retrieved — the following is generic advice". Do not keep asking, and do not refuse to answer.

**Mandatory four steps:**

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill explicitly instructs use of a bundled Python CLI, API-key handling, local config writes, and remote KaloData queries, but it does not declare any tool scope or permission boundaries. That creates an authorization and review gap: a consumer may invoke a skill with shell, network, environment, and file-write behavior without explicit least-privilege constraints or user-visible scoping.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The invocation guidance says to use the skill whenever the user researches TikTok Shop data, even if they never mention the tool. That can cause over-triggering of a networked, credit-consuming, credential-dependent skill in situations where the user did not intend external API use, increasing privacy, billing, and surprise-execution risk.

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 · SKILL.md (reported line 23)May include surrounding context.

python3 /scripts/kalo.py product rank --region US

text

All examples below write `kalo` as shorthand for `python3 <this-skill-dir>/scripts/kalo.py`.

Output is TOON (token-oriented) on stdout; add `--json` to any command for raw JSON.
Errors are structured on stdout with actionable `help:` lines. Exit codes: 0 ok, 1 error, 2 usage.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list includes broad phrases like "analyze this product," "why isn't it selling," and "how do I grow this," followed by "anything focused on a single product," which leaves activation boundaries loose. These phrases are common in ordinary conversation and the file does not provide negative examples or tighter constraints to prevent accidental matching.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Phrases such as "are they a good fit" and "anything focused on a single creator" are not specific enough to distinguish this playbook from general advisory or recommendation requests. Without clearer scope limits or negative examples, routine creator-related questions may incorrectly invoke this procedure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger examples include broad terms like "analyze category X" and "opportunities," then expand to "category-level landscape research," which is still open-ended. The description lacks explicit negative examples or stricter criteria for when this playbook applies versus more general analysis tasks.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Triggers like "video script," "shooting advice," and "what do viral videos have in common" are common requests and may not always imply this exact workflow. Although one exclusion is provided, the activation language remains broad enough to create collisions with adjacent playbooks or general assistance.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Phrases like "storyboard" and "write me a shooting script" are generic and the line also describes the playbook broadly as any scene-by-scene script for a production team. The file does not include enough exclusions to distinguish this trigger from general creative writing or editing assistance.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The instruction requires that dialogue be written in the target market's local language, which forces a locale-specific output mode rather than offering the user's preferred language as an option. The file does not present this as an opt-in choice or document a policy justification for overriding user language preference.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The client attaches the API key in the secret-key header and later sends requests upstream via urlopen, but this file does not include any confirmation prompt, user-facing logging, or inline warning about transmitting credentials to the external KaloData service. Because this is a code file performing outbound network communication with sensitive authentication material, some disclosure is expected unless it is clearly documented elsewhere.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The command surfaces and persists a language default as part of the skill configuration, but this file does not indicate any user opt-in, choice flow, or justification for enforcing a locale preference. Under the natural-language policy rule, locale-related behavior should either be optional or clearly documented as user-selected.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration hard-codes default locale-related values of region='US', language='en-US', and currency='USD'. This imposes a specific language/locale by default, and the file does not indicate user opt-in or justification for the constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code persists configuration values, including potentially sensitive fields such as the API key, to ~/.config/kalodata/config.toml. Although file permissions are restricted, there is no confirmation prompt, user-facing log/print, or inline warning explaining that sensitive configuration will be written to disk.

Content

No source excerpt is available for this finding.