Back to skill

Security audit

Dataify Agent Onboarding

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a Dataify onboarding helper, but it bundles broader scraping/reporting workflows and handles API tokens in ways users should review before installing.

Install only if you are comfortable letting the skill use your Dataify API token and send search terms, URLs, and task data to Dataify. Avoid using it with private/internal URLs or sensitive investigation targets unless you have reviewed the workflow scripts, and rotate the token if it may have appeared in logged task-status URLs.

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

Warning
Location
scripts/wait_for_task.py:35
Finding
API Token Exposed in URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wait_for_task.py`, lines 35–37; sensitive call sites at lines 103–106 and 128–131 **Vulnerability Type**: Credential exposure through URL query strings **Risk Level**: Medium ### 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 function is called with the API token included in `params`: ```python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, ) ``` The same pattern is used when downloading results: ```python return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, ) ``` ### Technical Analysis The Dataify API token is placed directly in the query string of status and download URLs. Although the endpoints use HTTPS, TLS only protects the request while it is in transit. Query strings can still be retained by HTTP server access logs, reverse proxies, gateways, observability platforms, debugging tools, and error reports. The response-body redaction performed later by the script does not protect the outbound request URL: ```python if api_key: text = text.replace(api_key, "<redacted>") ``` This only removes the token if Dataify reflects it in the response. It does not prevent the original URL from being logged. Transmitting authentication credentials in a URL exceeds the minimum exposure required for polling a task. The token should be sent through an authorization header instead. ### Attack Path 1. A user runs `wait_for_task.py` or a Builder workflow that invokes `wait_for_task`. 2. The script constructs requests such as: `https://scraperapi.dataify.com/ta ...[truncated 956 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `api_key` from all URL query parameters. 2. Authenticate using the standard 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 " + api_key}, method="GET", ) ``` 3. Update status and download calls so that only non-secret values are passed in `params`: ```python payload = request_json( STATUS_ENDPOINT, {"task_id": task_id}, api_key, request_timeout, ) ``` 4. If the remote API currently requires query-string authentication, update the service contract to support header-based credentials. Until that is possible: - Prevent request URLs from being logged. - Configure gateways and observability systems to redact `api_key`. - Use short-lived, narrowly scoped tokens where supported. 5. Add automated tests asserting that serialized request URLs never contain `DATAIFY_API_TOKEN` or an `api_key` parameter. 6. Rotate tokens that may already have appeared in request or infrastructure logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/catalog_builder.py:67
Finding
Shell Command Injection Through Generated Curl Preview<![CDATA[ ## Vulnerability Details **File Location**: `scripts/catalog_builder.py`, lines 67–77 **Vulnerability Type**: Shell command injection in generated command output **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 generated command is printed by preview mode: ```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` originates from a user-provided `--params-json` value or JSON file. It is interpolated into a single-quoted shell argument without shell escaping. JSON strings may legally contain apostrophes. An apostrophe in attacker-controlled data terminates the surrounding shell quote, after which shell metacharacters can introduce additional commands. Parsing and re-serializing the JSON does not remove apostrophes or make the result safe for shell interpolation. For example, a parameter value conceptually containing: ```text '; touch /tmp/dataify-preview-injected; # ``` can cause the generated preview to contain a command segment similar to: ```bash -d 'spider_parameters=[{"value":"'; touch /tmp/dataify-preview-injected; #"}]' ``` If that preview is copied into a shell or executed by an Agent, `touch /tmp/dataify-preview-injected` is interpreted as a separate command. The script does not execute the preview itself, which reduces immediate exploitability. However, preview ...[truncated 1411 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer structured preview output instead of generating an executable shell command. For example, print the endpoint, headers with a redacted token, and form fields as JSON. 2. If a shell command must be generated, apply `shlex.quote` separately to every complete argument: ```python import shlex def build_curl(tool, spider_parameters_json): arguments = [ "curl", "-X", "POST", BUILDER_URL, "-H", "Authorization: Bearer $DATAIFY_API_TOKEN", "-H", "Content-Type: application/x-www-form-urlencoded", "--data-urlencode", "spider_name={}".format(tool["spider_name"]), "--data-urlencode", "spider_id={}".format(tool["tool_sign"]), "--data-urlencode", "spider_parameters={}".format(spider_parameters_json), "--data-urlencode", "spider_errors=true", "--data-urlencode", "file_name={{TasksID}}", ] return " ".join(shlex.quote(argument) for argument in arguments) ``` 3. Clearly label preview output as untrusted and non-executable if it includes user-supplied content. 4. Avoid encouraging users or Agents to copy generated commands when the script can safely submit the request itself. 5. Add security tests using apostrophes, command substitutions, newlines, semicolons, backticks, and shell redirection characters in every user-controlled field. 6. Apply the same escaping to catalog-derived values such as `spider_name` and `tool_sign`, even if the current catalog is trusted, to preserve safety if catalog provenance changes. ]]>
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 (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs the agent to run a local Python script, inspect environment state, potentially read/write local files for telemetry, and route into network-backed capabilities, but it declares no permissions. That mismatch weakens user and platform oversight because the agent may perform sensitive operations the skill manifest does not transparently advertise.

Tp4

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
The declared purpose is onboarding, but the referenced behavior extends into executing downstream scraping, search, unlocker, and reporting workflows. This broader operational scope can cause users or reviewers to underestimate the data collection and execution capabilities exposed by the skill, increasing the chance of unexpected network actions or policy-violating use.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file implements generalized business-intelligence collection, scraping orchestration, and reporting that materially exceeds the onboarding/setup behavior declared in the skill manifest. This mismatch is dangerous because users and higher-level agents may invoke the skill expecting safe setup guidance, while it can instead collect and exfiltrate task data to external services under a misleading description.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
This code builds search and scraping actions, invokes external collection tools, and submits user-derived queries and URLs to remote services, none of which are necessary for first-time onboarding/setup. In the context of a setup skill, this is more dangerous because it creates covert data collection behavior behind an apparently benign integration-selection workflow.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The code synthesizes records, metrics, acceptance gates, and markdown/JSON intelligence reports, which is outside the stated onboarding purpose and indicates hidden analytical processing. While reporting itself is not inherently exploitable, in this context it evidences unauthorized scope expansion and persistence of collected data beyond what a user would reasonably expect from setup assistance.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function sends user-provided queries, subjects, URLs, and geography to external Dataify endpoints without any just-in-time disclosure or consent mechanism. In a skill presented as onboarding/setup, that undisclosed transmission is more sensitive because users are less likely to expect operational data collection or remote scraping during setup.

Missing User Warnings

Medium
Confidence
80% confidence
Finding
The search() and unlock() functions send user-provided queries and URLs to external Dataify endpoints, which can expose sensitive prompts, internal URLs, or private investigation targets to a third-party service if upstream callers pass them through without clear consent. In an onboarding skill, this is more concerning because users may expect setup assistance, not content transmission for live search/scraping, making inadvertent data disclosure more likely.

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