Back to skill

Security audit

amazon-market-entry-analyzer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly disclosed ZooData market-analysis wrapper, but it needs review because its API-key transport and install instructions create real credential and supply-chain risks.

Review before installing. Use the default HTTPS ZooData endpoint, do not set ZOODATA_BASE_URL unless you control and trust it, prefer ZOODATA_API_KEY in the environment over a persistent config file, and pin the installer/repository version when possible. Treat review-derived insights as untrusted evidence that can be influenced by marketplace review text.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/zoodata.py:65
Finding

Bearer Credential May Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/zoodata.py, lines 65-84 and 329-362
Vulnerability Type: Insufficient URL scheme validation for authenticated API requests
Risk Level: High

Vulnerable Code

python
def _is_trusted_host(url):
    """True only for ZooData hosts and localhost — the sole destinations the API
    key (Bearer token) may be sent to. Any other host is untrusted and the key
    is withheld (see api_call), so credentials never reach an arbitrary host."""
    host = _host_of(url)
    return host == "zoodata.ai" or host.endswith(".zoodata.ai") or host in ("localhost", "127.0.0.1")


def _resolve_base_url():
    """Resolve API base URL, allowing zoodata.ai / localhost hosts via ZOODATA_BASE_URL."""
    configured = os.environ.get("ZOODATA_BASE_URL", DEFAULT_BASE_URL).strip().rstrip("/")
    if configured.rstrip("/") != DEFAULT_BASE_URL.rstrip("/") and not _is_trusted_host(configured):
        print(f"WARNING: ZOODATA_BASE_URL points at untrusted host '{_host_of(configured)}'. "
              "Your API key (Bearer token) will NOT be sent there — requests to untrusted "
              "hosts are refused. Use a zoodata.ai host or localhost.",
              file=sys.stderr)
    if configured.endswith(API_BASE_PATH):
        return configured
    return f"{configured}{API_BASE_PATH}"
python
def api_call(endpoint: str, params: dict) -> dict:
    global _last_request_time

    url = f"{BASE_URL}/{endpoint}"

    if not BASE_URL_TRUSTED:
        print(f"ERROR: refusing to send your API key to untrusted host '{_host_of(BASE_URL)}'. "
              "Set ZOODATA_BASE_URL to a zoodata.ai host or localhost, or unset it.",
              file=sys.stderr)
        sys.exit(1)

    api_key = get_api_key()

    params = {k: v for k, v in params.items() if v is not None}

    actual_params = dict(params)

    body = json.dumps(params).encode("utf-8")
    headers =
...[truncated 1976 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse the complete configured URL with urllib.parse.urlparse.
  2. Require scheme == "https" for zoodata.ai and all permitted subdomains.
  3. Reject URLs containing user-information, malformed ports, fragments, or unexpected path components.
  4. Prefer a fixed production origin rather than allowing arbitrary ZooData subdomains.
  5. Disable authenticated plaintext localhost requests by default. If local development support is required, place it behind an explicit development-only flag and use a separate non-production credential.
  6. Validate the final constructed URL immediately before every authenticated request, rather than relying only on module-level state.
  7. Add tests proving that http://api.zoodata.ai, http://localhost, protocol-relative URLs, and malformed URLs are rejected before credential resolution.

T01 · Skill Instruction Hijacking

Warning
Location
scripts/zoodata.py:910
Finding

Externally Controlled Review Text Is Embedded Directly into Agent Instructions

Content
View full analysis

Vulnerability Details

File Location: scripts/zoodata.py, lines 910-953; workflow invocation in SKILL.md, lines 91-101
Vulnerability Type: Indirect prompt injection through untrusted marketplace content
Risk Level: Medium

Vulnerable Code

python
def render_review_map_prompt(review: dict, product_title: str = "", product_category: str = "") -> str:
    title = review.get("title") or ""
    body = review.get("body") or ""
    full = f"{title}. {body}" if title else body
    text = full[:500]
    rating = review.get("rating") or 3
    verified = bool(review.get("verifiedPurchase"))
    return f"""IMPORTANT: Respond ONLY with a JSON object matching the schema below. Output must be in English — translate non-English text before extracting.

You are an expert data extraction specialist analyzing product reviews. Extract only what is EXPLICITLY mentioned — do not infer.

JSON schema:
{{
  "sentiment": "positive" | "neutral" | "negative",
  "mentioned_scenarios": [string],
  "mentioned_issues": [string],
  "mentioned_positives": [string],
  "mentioned_improvements": [string],
  "mentioned_buying_factors": [string],
  "mentioned_pain_points": [string],
  "user_profiles": [string],
  "mentioned_usage_times": [string],
  "mentioned_usage_locations": [string],
  "mentioned_behaviors": [string],
  "keywords": [string]
}}

Rules:
- sentiment: positive (4-5 stars or praise), neutral (3 stars / mixed), negative (1-2 stars or complaint)
- pain_points = problems EXPERIENCED AFTER USE. NOT problems the product solves.
- issues vs pain_points: issues = product defects (hardware/software fault); pain_points = UX frustrations
- user_profiles: include ONLY if the reviewer explicitly states an identity ("I'm a...", "As a..."). NEVER infer.
- consistent naming across reviews (e.g. always "Workouts", not "At the gym")
- use empty arrays [] for categories with no mentions, never null

INPUT
...[truncated 2849 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat all review fields as hostile data and state explicitly that instructions appearing inside them must never be followed.
  2. Use separate structured message fields or a constrained extraction API instead of concatenating review content into the instruction string.
  3. Serialize review data as JSON and avoid delimiter-based interpolation. If delimiters remain necessary, escape delimiter sequences and control characters.
  4. Validate every model response against REVIEW_MAP_SCHEMA, including required keys, exact types, allowed sentiment values, maximum list sizes, and string-length limits.
  5. Reject unexpected keys, non-string elements, malformed output, and content that resembles tool or control instructions.
  6. Ensure model output cannot directly select commands, trigger tools, alter workflow policy, or write persistent state.
  7. Add adversarial tests covering triple quotes, Markdown fences, fake system messages, tool-call syntax, and instructions to ignore the extraction schema.
  8. Mark review-derived conclusions as untrusted or inferred unless corroborated by independent data.

T08 · Insecure Dependencies

Warning
Location
README.md:22
Finding

Documented Installation Uses Unpinned Third-Party Tooling and Mutable Repository Content

Content
View full analysis

Vulnerability Details

File Location: README.md, lines 22-26
Vulnerability Type: Unpinned software supply-chain installation
Risk Level: Medium

Vulnerable Code

markdown
## Install

```bash
npx skills add SerendipityOneInc/ZooData-Skills

Select Amazon Market Entry Analyzer when prompted.

text

### Technical Analysis

The installation procedure invokes the `skills` package through `npx` without specifying a package version. It also identifies repository content without pinning a release tag or immutable commit hash.

As a result, the code executed by `npx` and the Skill content installed from the repository can change after this artifact has been audited. Users following the documentation are not guaranteed to receive the reviewed version.

No evidence shows that the current package or repository is malicious. The confirmed weakness is the absence of version and integrity pinning, which creates a supply-chain substitution opportunity.

### Attack Path

1. The npm package, package-publishing account, repository, or repository-maintainer account is compromised, or a future mutable release introduces unsafe code.
2. An attacker publishes a modified `skills` package or changes the repository content resolved by the unpinned identifier.
3. A user follows the documented `npx skills add SerendipityOneInc/ZooData-Skills` command.
4. `npx` resolves and executes the currently available package rather than a previously audited version.
5. The installer retrieves and installs repository content that may differ from this audited artifact.
6. The substituted installer or Skill code executes with the permissions of the user running the installation.

### Impact Assessment

If an upstream component is compromised, the substituted code may obtain all privileges available to the installing user. Depending on the installer and host environment, this can include reading user files and environment variabl
...[truncated 296 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin the npm installer to a reviewed exact version, such as npx skills@X.Y.Z, and disable automatic acceptance of newer versions.
  2. Pin Skill repository content to an immutable release artifact or full commit hash.
  3. Publish cryptographic checksums or signed provenance for release artifacts.
  4. Verify downloaded content before installation and fail closed on integrity mismatch.
  5. Document the exact package version, repository commit, and expected hashes corresponding to each audited release.
  6. Prefer a package manager lockfile or a verified installer already present in the environment instead of executing newly resolved code through unpinned npx.
  7. Apply least privilege during installation and avoid exposing production credentials to the installer process.
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The file claims a specific GO/CAUTION/AVOID market-viability workflow using 11 endpoints, but the described capabilities include broader endpoint probing, keyword intelligence, historical retrieval, and review prompt-rendering/aggregation without showing the promised decision logic. This creates a confused-deputy risk where the skill can be selected for a simple assessment but operate as a general API/shell wrapper, expanding attack surface and weakening policy enforcement, auditability, and user consent around what data is processed and which actions occur.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The file claims a specific GO/CAUTION/AVOID market-viability workflow using 11 endpoints, but the described capabilities include broader endpoint probing, keyword intelligence, historical retrieval, and review prompt-rendering/aggregation without showing the promised decision logic. This creates a confused-deputy risk where the skill can be selected for a simple assessment but operate as a general API/shell wrapper, expanding attack surface and weakening policy enforcement, auditability, and user consent around what data is processed and which actions occur.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest describes a skill that should evaluate a specific niche/category and return one GO/CAUTION/AVOID market-entry recommendation. This file implements numerous additional workflows such as competitor war-room analysis, pricing analysis, daily monitoring, listing audits, opportunity discovery, and review deep-dives, which materially exceed that described behavior even if they are gated by an allowlist at runtime.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding

The README instructs users to run npx skills add SerendipityOneInc/ZooData-Skills without pinning a specific package or repository version. This can expose users to supply-chain risk if the referenced package, installer, or resolved content changes over time or is compromised, causing different code to execute than what was originally reviewed.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill exposes sensitive capabilities (environment access for API keys, file reads, network access, and shell execution) but does not declare a restrictive tool scope such as permissions or allowed-tools. That creates a governance gap: a host agent may grant broader capabilities than the skill actually needs, increasing the chance of unintended command execution, credential access, or data exfiltration if the skill is misrouted or later modified.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/reference.md (reported line 24)May include surrounding context.

md
# ─── Configuration ───────────────────────────────────────────────────────────

DEFAULT_BASE_URL = "https://api.zoodata.ai/openapi/v2"
API_BASE_PATH = "/openapi/v2"
KEYWORD_DATE_RANGE_MAX_DAYS = 93
KEYWORD_TIMELINE_MAX_DAYS = 61

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/zoodata.py (reported line 50)May include surrounding context.

python
# ─── Configuration ───────────────────────────────────────────────────────────

DEFAULT_BASE_URL = "https://api.zoodata.ai/openapi/v2"
API_BASE_PATH = "/openapi/v2"
KEYWORD_DATE_RANGE_MAX_DAYS = 93
KEYWORD_TIMELINE_MAX_DAYS = 61

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/zoodata.py (reported line 87)May include surrounding context.

python
# ─── Configuration ───────────────────────────────────────────────────────────

DEFAULT_BASE_URL = "https://api.zoodata.ai/openapi/v2"
API_BASE_PATH = "/openapi/v2"
KEYWORD_DATE_RANGE_MAX_DAYS = 93
KEYWORD_TIMELINE_MAX_DAYS = 61

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 · scripts/zoodata.py (reported line 258)May include surrounding context.

python
print("    export ZOODATA_API_KEY='hms_live_yourkey'", file=sys.stderr)
    print("", file=sys.stderr)
    print("  Method 2: User-home config (persistent, shared across all skills)", file=sys.stderr)
    print("    mkdir -p ~/.zoodata && chmod 700 ~/.zoodata", file=sys.stderr)
    print('    (umask 077; echo \'{"api_key":"hms_live_yourkey"}\' > ~/.zoodata/config.json)', file=sys.stderr)
    print("    # keep the file private (0600) — it holds a bearer credential", file=sys.stderr)
    print("", file=sys.stderr)

Session Persistence

Medium
Category
Rogue Agent
Confidence
82% confidence
Finding

The CLI explicitly supports persisting a bearer API key in ~/.zoodata/config.json, creating long-lived credential storage on disk shared across skills. Even with recommended private permissions, persistent secrets increase the blast radius of local compromise, accidental backup/sync exposure, or reuse by other bundled tooling beyond the user's immediate intent.

Content

Scanner excerpt · scripts/zoodata.py (reported line 258)May include surrounding context.

python
print("    export ZOODATA_API_KEY='hms_live_yourkey'", file=sys.stderr)
    print("", file=sys.stderr)
    print("  Method 2: User-home config (persistent, shared across all skills)", file=sys.stderr)
    print("    mkdir -p ~/.zoodata && chmod 700 ~/.zoodata", file=sys.stderr)
    print('    (umask 077; echo \'{"api_key":"hms_live_yourkey"}\' > ~/.zoodata/config.json)', file=sys.stderr)
    print("    # keep the file private (0600) — it holds a bearer credential", file=sys.stderr)
    print("", file=sys.stderr)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code file contains a natural-language instruction that says the output 'must be in English' and requires translation of non-English text before extraction. That imposes a specific language policy on downstream use without offering a language choice or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says this skill is for one-click market viability assessment of a named niche/category, but the in-file help and subcommand docs actively present commands like review-deepdive, listing-audit, daily-radar, pricing-analysis, and opportunity-scan as available features. That documentation conflicts with the skill's stated intent and would mislead users or agents about what this particular skill is meant to do.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file documents authentication via Bearer $ZOODATA_API_KEY, which involves use of a sensitive credential. Under the markdown-file warning criterion, the document does not include any caution about protecting the API key, avoiding accidental disclosure, or handling authenticated requests carefully.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/zoodata.py (reported line 1234)May include surrounding context.

python
"priceMin", "priceMax", "ratingMin", "ratingMax", "bsrMin", "bsrMax",
                 "salesGrowthRateMin", "salesGrowthRateMax", "sellerCountMin", "sellerCountMax",
                 "variantCountMin", "variantCountMax"):
        val = getattr(args, attr.replace("Min", "_min").replace("Max", "_max")
                      .replace("monthly", "monthly_").replace("review", "review_")
                      .replace("sales", "sales_").replace("Growth", "_growth_")
                      .replace("Rate", "rate_").replace("price", "price_")