Back to skill

Security audit

Dataify MCP

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly describes Dataify MCP setup, but the package also contains under-disclosed scraping/business workflow code and stores Dataify tokens in MCP configuration URLs and backups.

Review this skill before installing. Use it only if you are comfortable with your Dataify API token being written into MCP client configuration files and possibly backup files, and avoid invoking the bundled business workflow or task-polling scripts unless you separately intend to run Dataify scraping/search workflows. Consider using a limited-scope token and rotating it after testing.

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 Through GET Query Parameters## Vulnerability Details **File Location**: `scripts/wait_for_task.py`, lines 35–39, 100–107, and 128–134 **Vulnerability Type**: Sensitive credential exposure through URL query parameters **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 polling operation passes the API token as part of `params`: ```python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, ) ``` The result-download operation repeats the same credential transport: ```python if status == SUCCESS_STATUS: return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, ) ``` ### Technical Analysis `request_json` serializes every parameter into the URL and performs a GET request. Consequently, `DATAIFY_API_TOKEN` becomes part of request URLs sent to both `/task_status` and `/download`. HTTPS protects the URL from passive network observers while it is in transit, but it does not prevent the URL from being recorded at its endpoints or within trusted infrastructure. Query strings may be captured by reverse-proxy access logs, server request logs, application-performance monitoring, debugging systems, exception telemetry, or network inspection products. Replacing the API key in the response body at line 61 does not protect the request URL. The credential has already been transmitted as URL metadata before response redaction occurs. This network access is necessary for task polling, but placing the credential in a query parameter exceeds the minimum exposure ...[truncated 1099 chars]
Remediation
## Remediation Suggestions 1. Remove `api_key` from all URL query parameters. 2. Send the token in an authorization header, for example: ```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", ) ``` 3. Keep only non-secret values such as `task_id` and `type` in the query string. 4. If the current Dataify API requires query-string authentication, update the service API to support authorization headers before changing the client. 5. Configure server, proxy, monitoring, and telemetry systems to redact existing `api_key` query parameters. 6. Rotate tokens that may already have appeared in request logs and establish a retention policy for historical logs. 7. Add automated tests asserting that generated request URLs never contain the API token.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/configure_mcp.py:108
Finding
API Token Persisted in Plaintext MCP URLs and Backup Files## Vulnerability Details **File Location**: `scripts/configure_mcp.py`, lines 108–151 and 182–189 **Vulnerability Type**: Plaintext credential storage and duplication **Risk Level**: Medium ### Vulnerable Code The TOML configuration path embeds the token in the MCP URL and may copy an existing credential-bearing file to a predictable backup: ```python def configure(path: Path, token: str, tools: list[str], write: bool = False) -> dict: if not token.strip(): raise RuntimeError("DATAIFY_API_TOKEN is not configured") tools = validate_tools(tools) if path.suffix == '.toml': text = path.read_text(encoding='utf-8') if path.exists() else '' tomllib.loads(text) sections = re.split(r'(?m)(?=^\[)', text) text = ''.join(section for section in sections if not re.match(r'\[mcp_servers\.dataify(?:\.|\])', section)) url = 'https://mcp.dataify.com/mcp?token={}&tools={}'.format(quote(token.strip(), safe=''), ','.join(tools)) updated = text.rstrip() + '\n\n[mcp_servers.dataify]\nurl = ' + json.dumps(url) + '\n' tomllib.loads(updated) if write: path.parent.mkdir(parents=True, exist_ok=True) if path.exists(): shutil.copy2(path, path.with_suffix('.toml.bak')) fd, temporary = tempfile.mkstemp(dir=path.parent) with os.fdopen(fd, 'w', encoding='utf-8') as handle: handle.write(updated) os.replace(temporary, path) return {'client_config':str(path), 'written':write, 'tools':tools, 'credential':'configured'} ``` The JSON configuration path has the same behavior: ```python url = "https://mcp.dataify.com/mcp?token={}&tools={}".format( quote(token.strip(), safe=""), ",".join(tools) ) existing["mcpServers"]["dataify"] = {"url": url} backup = None if write: path.parent.mkdir(parents=True, exist_ok=True) if path. ...[truncated 3375 chars]
Remediation
## Remediation Suggestions 1. Prefer MCP client support for environment-variable interpolation or authorization headers instead of storing the token in the URL. 2. Where supported, configure the endpoint and credential separately, for example with an environment reference rather than the resolved secret value. 3. If plaintext storage is unavoidable due to client limitations: - Warn the user explicitly before `--write`. - Create configuration files with owner-only permissions. - Verify and correct permissions after `os.replace`. - Reject unsafe destinations such as shared or world-readable directories. 4. Do not create plaintext backups containing credentials by default. Require explicit backup consent or produce a sanitized backup that removes credential-bearing fields. 5. Remove obsolete `.bak` files after successful migration, subject to user approval. 6. Avoid token-bearing verification URLs where the protocol supports header-based authentication. 7. Add tests verifying that inspection, errors, command output, and logs never contain the resolved token. 8. Document credential rotation procedures for users who previously generated plaintext configurations or backups.
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 (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs the agent to read environment variables, inspect and write MCP configuration files, invoke local scripts, and verify connectivity, yet it declares no permissions. This creates a trust and review gap: operators may authorize or run the skill under the assumption it is low-privilege when it actually has file, shell, env, and network reach.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The declared purpose says the skill is only for MCP setup and tool selection, but the analyzer indicates the bundled behavior extends into broad data collection, scraping, task submission, and business intelligence workflows. That mismatch is dangerous because users and reviewers may grant access for a narrow setup task while the skill can drive much broader network activity and potentially collect external data beyond the stated scope.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
This file implements broad business-intelligence collection, scraping, record extraction, and reporting workflows even though the skill is advertised as MCP configuration/setup only. That mismatch expands the skill's real capabilities far beyond user expectations and creates an unjustified data-exfiltration and web-collection surface inside a setup-oriented skill.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The code executes external analysis capabilities via local helper scripts and direct HTTP requests to Dataify endpoints, enabling active data collection unrelated to MCP setup or repair. In the context of a setup-only skill, that is dangerous because it silently turns a configuration utility into an operational scraping/search agent with network reach.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The workflow requires and consumes an API token to run external data-collection actions, despite the enclosing skill being described as MCP setup-focused. This increases risk because users may supply credentials under the assumption they are only needed for configuration, while the code actually uses them to perform searches and scraping against external services.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The module docstring explicitly describes 'business skills,' which conflicts with the stated MCP setup-only purpose of the enclosing skill. That discrepancy is a strong indicator of scope smuggling: hidden or repurposed functionality can mislead reviewers and users about what the skill actually does.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This file exposes general-purpose `search()` and `unlock()` capabilities that perform ordinary web search and page retrieval/scraping, which conflicts with the skill's declared scope of MCP configuration and verification only. In an agent skill, this kind of scope drift is dangerous because it silently gives the agent data-exfiltration and arbitrary web-access functionality beyond what users and policy reviewers would reasonably expect from the manifest.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The direct requests send user-provided search subjects and URLs to external Dataify services without an obvious user-facing disclosure at the collection call sites. In a setup-oriented skill, undisclosed transmission of user inputs to third-party endpoints is especially risky because users are unlikely to expect operational scraping or search queries during configuration work.

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