Back to skill

Security audit

Dataify API Best Practices

Security checks for vulnerabilities and agentic risk

Overview

The skill is packaged as Dataify integration guidance but includes under-disclosed live business-intelligence workflows and insecure credential/command handling, so it should be reviewed before install.

Install only if you specifically need Dataify integration helpers and are comfortable reviewing the shipped scripts. Do not run the business workflow helpers unless you intend live Dataify collection and credit use, rotate any token that may have been used with task URLs, and treat generated curl or resume commands as untrusted until properly quoted or validated.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wait_for_task.py:35
Finding

API Token Exposed in Task Request URL Query Strings

Content
View full analysis

Vulnerability Details

File Location: scripts/wait_for_task.py:35-39, with sensitive call sites at scripts/wait_for_task.py:104-108 and scripts/wait_for_task.py:129-134
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: High

Vulnerable Code:

python
def request_json(endpoint, params, api_key, timeout):
    url = endpoint + "?" + urllib.parse.urlencode(params)
    request = urllib.request.Request(url, method="GET")
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            content = response.read()

The API key is supplied through params at both task-processing call sites:

python
payload = request_json(
    STATUS_ENDPOINT,
    {"api_key": api_key, "task_id": task_id},
    api_key,
    request_timeout,
)
python
return request_json(
    DOWNLOAD_ENDPOINT,
    {"api_key": api_key, "task_id": task_id, "type": "json"},
    api_key,
    request_timeout,
)

Technical Analysis

request_json() URL-encodes all parameters, including api_key, directly into the request URL. Although HTTPS protects the URL while it is in transit, URL query strings are frequently retained by reverse-proxy access logs, API gateway logs, network observability products, exception reports, monitoring infrastructure, and server-side request telemetry.

The response redaction performed later in the function only replaces the API key if it appears in the response body. It does not protect the outgoing request URL or any infrastructure logs that record it.

This behavior also conflicts with the package's documented authentication contract, which requires DATAIFY_API_TOKEN to be transmitted as an HTTP Bearer credential. Authentication is necessary for the declared functionality, but exposing the credential in a URL exceeds the minimum safe disclosure required.

Attack Path

  1. A user submits a Dataify Bui ...[truncated 1014 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove api_key from all status and download query-parameter dictionaries.

  • Send the credential exclusively through an authorization header:

    python
    def request_json(endpoint, params, api_key, timeout):
        url = endpoint + "?" + urllib.parse.urlencode(params)
        request = urllib.request.Request(
            url,
            headers={"Authorization": "Bearer {}".format(api_key)},
            method="GET",
        )
    
  • Keep only non-secret values, such as task_id and response type, in the query string.

  • Confirm that Dataify's task endpoints support Bearer authentication and update the integration contract consistently.

  • Configure proxies, API gateways, and application telemetry to redact authorization headers.

  • Rotate any token that may already have appeared in request logs.

  • Add automated tests asserting that generated URLs never contain the token or an api_key parameter.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/catalog_builder.py:68
Finding

Shell Command Injection in Generated Builder Preview

Content
View full analysis

Vulnerability Details

File Location: scripts/catalog_builder.py:68-78 and scripts/catalog_builder.py:121-127
Vulnerability Type: Shell command injection through unsafe command generation
Risk Level: Medium

Vulnerable Code:

python
def build_curl(tool, spider_parameters_json):
    return " \\\n".join([
        "curl -X POST '{}'".format(BUILDER_URL),
        "  -H 'Authorization: Bearer $DATAIFY_API_TOKEN'",
        "  -H 'Content-Type: application/x-www-form-urlencoded'",
        "  -d 'spider_name={}'".format(tool["spider_name"]),
        "  -d 'spider_id={}'".format(tool["tool_sign"]),
        "  -d 'spider_parameters={}'".format(spider_parameters_json),
        "  -d 'spider_errors=true'",
        "  -d 'file_name={{TasksID}}'",
    ])

The resulting command is printed by the preview path:

python
payload_json = json.dumps(rows, ensure_ascii=False, separators=(",", ":"))
if args.preview:
    print(build_curl(tool, payload_json))
    return 0

Technical Analysis

spider_parameters_json contains user-controlled values loaded from --params-json or --values-file. It is inserted directly into a single-quoted shell argument without shell escaping.

JSON strings may legally contain apostrophes. An apostrophe in a supplied value terminates the generated shell argument, after which shell operators and commands can be inserted. The script does not execute the generated command itself, so exploitation requires an operator or an automated agent to copy and execute the advertised curl preview. Nevertheless, the output is explicitly formatted as an executable command and may reasonably be trusted by users.

The same quoting weakness also applies to dynamic catalog fields such as spider_name and tool_sign if the catalog source becomes attacker-controlled.

Attack Path

  1. An attacker supplies a crafted parameter value through --params-json or a values file.

...[truncated 925 chars]

Remediation
View remediation

Remediation Suggestions

  • Prefer a non-executable structured preview, such as JSON containing the HTTP method, endpoint, headers with credentials redacted, and form fields.

  • If a shell command is required, quote every dynamic argument with shlex.quote() rather than manually surrounding values with apostrophes.

  • Construct each complete form argument before quoting it:

    python
    import shlex
    
    fields = [
        "spider_name={}".format(tool["spider_name"]),
        "spider_id={}".format(tool["tool_sign"]),
        "spider_parameters={}".format(spider_parameters_json),
        "spider_errors=true",
        "file_name={{TasksID}}",
    ]
    command = ["curl", "-X", "POST", BUILDER_URL]
    for field in fields:
        command.extend(["-d", field])
    preview = " ".join(shlex.quote(value) for value in command)
    
  • Avoid presenting generated shell text as safe to execute unless hostile input tests cover apostrophes, command substitutions, newlines, backticks, semicolons, and shell metacharacters.

  • Keep the token represented as an environment-variable reference and never expand or print its value in preview output.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/wait_for_task.py:91
Finding

Shell Command Injection in Generated Task Recovery Commands

Content
View full analysis

Vulnerability Details

File Location: scripts/wait_for_task.py:91-94; equivalent command generation also occurs at scripts/task_runtime.py:50-53 and scripts/task_runtime.py:57-60
Vulnerability Type: Shell command injection through unvalidated task identifiers
Risk Level: Medium

Vulnerable Code:

python
def resume_command(task_id, timeout):
    script_path = os.path.abspath(__file__)
    return 'python3 "{}" --task-id "{}" --timeout {}'.format(script_path, task_id, int(timeout))

Equivalent recovery-command construction in task_runtime.py:

python
waiter = os.path.abspath(os.path.join(os.path.dirname(__file__), "wait_for_task.py"))
command = 'python3 "{}" --task-id "{}" --timeout {}'.format(
    waiter, task_id, int(float(wait_timeout))
)
raise RuntimeError("{}\nResume: {}".format(exc, command)) from None
python
waiter = os.path.abspath(os.path.join(os.path.dirname(__file__), "wait_for_task.py"))
command = 'python3 "{}" --task-id "{}" --timeout {}'.format(
    waiter, task_id, int(float(wait_timeout))
)
raise RuntimeError(
    "Monitoring interrupted. Do not resubmit the task.\nResume: {}".format(command)
) from None

Technical Analysis

The task identifier is inserted inside a double-quoted shell command without validation or shell escaping. A task ID containing a double quote can terminate the intended argument and append shell operators or command substitutions.

In wait_for_task.py, task_id comes directly from the --task-id command-line option and is only stripped and checked for non-emptiness. In task_runtime.py, it can originate from a Builder API response through extract_task_id(). Dictionary-based task IDs are converted to strings without applying the allowlist that is used only for plain-string response payloads.

The generated command is printed after a timeout or interruption rather than executed directly. Exploitation therefore re ...[truncated 1133 chars]

Remediation
View remediation

Remediation Suggestions

  • Validate every task ID at all trust boundaries with a strict allowlist consistent with the existing extraction logic:

    python
    if not re.fullmatch(r"[A-Za-z0-9_-]{8,128}", task_id):
        raise ValueError("Invalid task ID")
    
  • Apply validation both to CLI input and every task ID extracted from an API response, including values found in dictionaries.

  • Avoid emitting shell command strings. Return a structured argument array or separate recovery fields instead:

    python
    {
        "program": sys.executable,
        "arguments": [script_path, "--task-id", task_id, "--timeout", str(int(timeout))]
    }
    
  • If a copyable shell command is necessary, use shlex.quote() for POSIX shells and a platform-specific quoting implementation for Windows.

  • Add tests using task IDs containing quotes, newlines, command substitutions, semicolons, spaces, and backticks, and verify that invalid identifiers are rejected before command generation.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description says it should not be used for account setup, yet the policy includes token setup guidance, shell/OS detection, and credential-verification flow. This contradiction broadens the skill from code review into credential-handling and environment configuration, which is sensitive because it encourages privileged environment interaction beyond the stated purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description says it should not be used for account setup, yet the policy includes token setup guidance, shell/OS detection, and credential-verification flow. This contradiction broadens the skill from code review into credential-handling and environment configuration, which is sensitive because it encourages privileged environment interaction beyond the stated purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file implements a full autonomous business-intelligence workflow: generating search/scraping actions, collecting external data, enriching results, and producing reports on prices, reviews, leads, and brand monitoring. That behavior materially exceeds the declared skill purpose of writing/reviewing/debugging Dataify integration code, creating a scope mismatch that can be abused to perform operational reconnaissance and data collection under misleading packaging.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The action-generation logic creates autonomous market, review, lead, and brand-research tasks from user inputs, including competitor, keyword, source URL, geography, and freshness parameters. In the context of a skill advertised as API best-practices guidance, these capabilities are dangerous because they enable substantive external intelligence gathering unrelated to the stated safe coding-assistance role.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This code executes external search and scraping tools and falls back to direct HTTP requests against Dataify endpoints, allowing the skill to operationalize real collection rather than merely discuss integrations. That is especially concerning here because the manifest says the skill should help write or debug integration code, not perform live searches, scraping, or intelligence acquisition itself.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises operational behaviors that imply access to environment variables, files, network, and shell-like execution, but it does not declare any explicit tool scope or permission boundaries. This creates an authorization ambiguity: an agent/runtime may grant broader capabilities than the user expects, increasing the risk of overreach, secret access, or unintended external actions.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
## Account CTA policy

- Show a prominent Dataify account CTA only when the API token is missing, rejected/invalid, or the account has insufficient credits.
- For a missing token, offer https://dashboard.dataify.com/login?utm_source=skill and state: New accounts get 50 free credits, enough for about 6,000 trial results, valid for 7 days, and only successful requests are billed. Never ask the user to paste the token into chat.
- Detect the current operating system and shell. Show only the matching session-scoped setup command first (`export` for macOS/Linux shells, `$env:` for Windows PowerShell, or `set` for Windows Command Prompt). Show other platforms or persistent setup only when detection is ambiguous or the user asks.
- After the user says the token is configured, verify only whether `DATAIFY_API_TOKEN` is present; never print its value. If verification succeeds, continue the original task without asking the user to repeat it.
- Explain that persistent shell changes may require a new terminal or restarting the agent application. Do not recommend a project `.env` unless the execution path explicitly loads it, and ensure `.env` is ignored by version control.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
- Show a prominent Dataify account CTA only when the API token is missing, rejected/invalid, or the account has insufficient credits.
- For a missing token, offer https://dashboard.dataify.com/login?utm_source=skill and state: New accounts get 50 free credits, enough for about 6,000 trial results, valid for 7 days, and only successful requests are billed. Never ask the user to paste the token into chat.
- Detect the current operating system and shell. Show only the matching session-scoped setup command first (`export` for macOS/Linux shells, `$env:` for Windows PowerShell, or `set` for Windows Command Prompt). Show other platforms or persistent setup only when detection is ambiguous or the user asks.
- After the user says the token is configured, verify only whether `DATAIFY_API_TOKEN` is present; never print its value. If verification succeeds, continue the original task without asking the user to repeat it.
- Explain that persistent shell changes may require a new terminal or restarting the agent application. Do not recommend a project `.env` unless the execution path explicitly loads it, and ensure `.env` is ignored by version control.
- For an invalid token, direct the user to API-key management without implying that a new registration is required. For insufficient credits, direct the user to balance or recharge management.
- During normal submission, processing, and successful completion, do not promote registration or the Dashboard. Never expose the token or include it in CTA attribution parameters.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/business_workflow.py (reported line 180)May include surrounding context.

python
def execute_action(action: dict[str, Any], token: str) -> subprocess.CompletedProcess[str]:
    invocation = command(action)
    if len(invocation) > 1 and Path(invocation[1]).exists():
        return subprocess.run(invocation, capture_output=True, text=True, encoding="utf-8", errors="replace", check=False)
    if action.get('capability', '').startswith('scraper-'):
        return subprocess.CompletedProcess([], 1, '', 'Required platform scraper is not installed; install it before executing this action.')
    return direct_request(action, token)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The analysis and reporting pipeline computes commercial and reputational metrics, applies acceptance gates, and emits structured intelligence reports and markdown summaries. This transforms collected data into decision-support artifacts, reinforcing that the skill is functioning as an autonomous business-intelligence tool rather than a best-practices coding assistant, which increases the risk of deceptive or unauthorized use.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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/catalog_builder.py (reported line 70)May include surrounding context.

python
def build_curl(tool, spider_parameters_json):
    return " \\\n".join([
        "curl -X POST '{}'".format(BUILDER_URL),
        "  -H 'Authorization: Bearer $DATAIFY_API_TOKEN'",
        "  -H 'Content-Type: application/x-www-form-urlencoded'",
        "  -d 'spider_name={}'".format(tool["spider_name"]),

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest says this skill should be used to write, review, or debug Dataify integration code and explicitly says not to use it for account setup. However, the runtime error text instructs users to sign in via the dashboard and advertises free credits and billing details, which is operational onboarding behavior rather than integration-code behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script hard-codes natural-language task status strings in Chinese ("处理中", "成功", "失败") and treats any other status as an error. This creates an implicit language/locale dependency without user opt-in or documentation that the skill is intentionally region-specific, which matches the locale policy violation criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The comment states that URL filtering is intended so redirects and metadata URLs do not consume a research workflow's fetch budget. That documented intent conflicts with the manifest, which explicitly excludes research as a supported use case for this skill.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/task_runtime.py:38