Back to skill

Security audit

Dataify API Best Practices

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a Dataify integration helper, but it includes under-disclosed live scraping and business-intelligence workflows plus insecure token handling that should be reviewed before installation.

Install only if you are comfortable with a Dataify package that may be used for live external API calls and local report generation, not just static integration review. Before use, review or remove the business_workflow scripts, avoid running generated curl previews with untrusted input, and rotate or restrict any DATAIFY_API_TOKEN if it may have been used with query-string polling.

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:105
Finding
API Token Exposed in HTTP Query Strings<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wait_for_task.py:35-39, 105-109, 127-130` **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: ``` ```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 The API token is inserted into the query string of status and download requests. Although the connection uses HTTPS, URLs are commonly recorded by reverse proxies, API gateways, server access logs, monitoring systems, exception telemetry, and debugging tools. The subsequent response-body replacement: ```python if api_key: text = text.replace(api_key, "<redacted>") ``` does not protect the outbound request URL or infrastructure logs. This implementation also conflicts with the project's documented authentication contract, which requires `Authorization: Bearer <environment value>`. ### Attack Path 1. A legitimate user runs `wait_for_task.py` or a Builder workflow that calls `complete_task()`. 2. The script sends requests such as `/task_status?api_key=TOKEN&task_id=...`. 3. An operator, compromised monitoring account, log collector, proxy administrator, or other party with URL-log access obtains the complete request URL. 4. The party extracts the API token from the `api_key` parameter. 5. The exposed token is reused against Dataify endpoints until it is revoked or expires. ### Impact Assessment Successful exploitation exposes the privileges assigned to the Da ...[truncated 326 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `api_key` from all URL query parameters. - Send the credential through an HTTP authorization header: ```python request = urllib.request.Request( url, headers={"Authorization": "Bearer {}".format(api_key)}, method="GET", ) ``` - If the remote API cannot accept authorization headers, prefer an authenticated POST request with the credential outside the URL and confirm that request bodies are excluded from logs. - Ensure error messages, telemetry, debug output, and HTTP tracing redact both raw and `Bearer`-prefixed token values. - Rotate any token that may already have appeared in access logs. - Add tests asserting that generated URLs never contain `DATAIFY_API_TOKEN` or an `api_key` credential parameter. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dataify_client.py:34
Finding
Public-URL Validation Allows Private and Local Network Targets<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dataify_client.py:34-41` **Vulnerability Type**: Incomplete SSRF target validation **Risk Level**: Medium ### Vulnerable Code ```python def normalize_url(value: str) -> str: value = value.strip() parts = urlsplit(value) if parts.scheme not in {"http", "https"} or not parts.netloc: raise ValueError("A public HTTP(S) URL is required") if parts.username or parts.password or not re.fullmatch(r"[A-Za-z0-9.-]+(?::\d+)?", parts.netloc): raise ValueError("URL credentials or invalid host names are not allowed") return value ``` The business workflow also forwards URL actions directly to the Web Unlocker without applying this validator: ```python payload = {"url": action["url"], "type": "html", "js_render": "True", "clean_content": "true", "country": str(action.get("geography", "us")).lower(), "follow_redirect": "True", "isjson": "1"} request = urllib.request.Request( "https://webunlocker.dataify.com/request", data=json.dumps(payload).encode("utf-8"), headers={"Authorization": "Bearer {}".format(token), "Content-Type": "application/json"}, method="POST", ) ``` ### Technical Analysis `normalize_url()` verifies only the URL scheme, presence of a host, absence of embedded credentials, and basic hostname syntax. It does not establish that the destination is public, despite its error message and the documented Web Unlocker contract. The validation can accept hostnames or textual addresses that resolve to: - Loopback interfaces - RFC1918 private networks - Link-local networks - Reserved or multicast ranges - IPv6 local networks - Cloud instance metadata services - Public hostnames that resolve or rebind to private addresses The business workflow's `--source-url` path is less restrictive because it forwards the supplied URL without calling `normalize_url()`. Whether a target is ultimately reachable depends on server-side protections implemented ...[truncated 1232 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Parse and canonicalize the hostname before submission. - Resolve all IPv4 and IPv6 addresses associated with the hostname. - Reject loopback, private, link-local, multicast, unspecified, reserved, and metadata-service address ranges. - Apply the same validation to every URL path, including `business_workflow.py --source-url` and URLs extracted from search results. - Reject ambiguous numeric host representations and normalize internationalized domain names before validation. - Revalidate the destination after every redirect. - Protect against DNS rebinding by binding validation and connection to the same resolved address where possible. - Retain server-side egress filtering and metadata-service blocking as defense in depth. - Add tests for `localhost`, private IPv4 ranges, loopback, link-local addresses, IPv6 local addresses, metadata hosts, and public hostnames resolving to prohibited addresses. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/catalog_builder.py:68
Finding
Shell Injection in Generated Builder Preview Command<![CDATA[ ## Vulnerability Details **File Location**: `scripts/catalog_builder.py:68-79, 125-128` **Vulnerability Type**: Command injection through unsafe shell-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}}'", ]) ``` ```python payload_json = json.dumps(rows, ensure_ascii=False, separators=(",", ":")) if args.preview: print(build_curl(tool, payload_json)) return 0 ``` ### Technical Analysis Builder parameter JSON is interpolated directly into a command enclosed with single quotes. JSON strings can legally contain apostrophes. An attacker-controlled apostrophe terminates the shell quoting context, after which shell metacharacters can introduce additional commands. The Python script only prints the command and does not execute it. Exploitation therefore requires a user or automated agent to copy or execute the generated preview. Nevertheless, the output is explicitly formatted as a ready-to-run `curl` command, making this a credible command-generation vulnerability. For example, a malicious parameter value can conceptually close the `-d` argument, append a shell command, and comment out the remainder. The exact payload would be carried unchanged into `spider_parameters_json`. ### Attack Path 1. An attacker supplies a crafted JSON parameter file or `--params-json` value containing an apostrophe followed by shell syntax. 2. A user runs `catalog_builder.py --preview`. 3. `build_curl()` inserts the value into a single-quoted ...[truncated 678 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Prefer a structured JSON preview rather than generating an executable shell command. - If a shell command must be generated, quote every dynamic argument with `shlex.quote()`: ```python import shlex argument = "spider_parameters={}".format(spider_parameters_json) preview = "curl ... --data {}".format(shlex.quote(argument)) ``` - Apply shell quoting independently to `spider_name`, `tool_sign`, parameter JSON, and every other dynamic field. - Clearly label generated commands as display-only and avoid automatically passing them to `shell=True`, `eval`, or a shell interpreter. - For execution, use `subprocess.run()` with an argument list and `shell=False` rather than constructing a command string. - Add regression tests using apostrophes, newlines, command substitutions, semicolons, backticks, and other shell metacharacters in Builder parameters. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill clearly instructs the agent to read environment variables, read local files, run a shell command, and reference external URLs/APIs, yet no permissions are declared. That creates a trust and containment problem: reviewers and policy systems cannot accurately reason about what the skill may access, increasing the risk of unintended secret access or execution in a broader context.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description frames the skill as a narrow code-writing/review aid, but the body authorizes live API execution, builder job submission, polling, data collection, and account/token setup flows. This mismatch can cause the skill to be invoked in contexts where only static guidance was expected, leading to unanticipated external actions, credit consumption, and handling of sensitive credentials.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This file implements live external collection and scraping orchestration even though the skill manifest says the skill should only write, review, or debug Dataify integration code. That mismatch materially expands the skill's behavior into operational reconnaissance/data collection, which can cause unauthorized outbound activity and exfiltration of user-supplied targets to external services.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code defines lead, review, price, and brand intelligence workflows unrelated to the stated purpose of integration-code assistance. Embedding these capabilities in a coding-assistance skill increases the risk that the agent can be repurposed for scraping, competitive intelligence, or target profiling without users realizing the true operational scope.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
User-supplied queries and URLs are transmitted to external Dataify endpoints without an explicit disclosure or consent step at execution time. In a skill presented as coding help, that hidden transmission is risky because sensitive subjects, internal URLs, or investigative targets may be sent off-box unexpectedly.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- 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.
Confidence
77% confidence
Finding
The skill instructs the agent to continue the original task automatically after verifying that the token is present, without re-confirming the action. In a skill that can trigger live third-party requests and billable operations, this reduces user control and can lead to unintended external calls or charges once credentials become available.

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