Back to skill

Security audit

widehive

Security checks for vulnerabilities and agentic risk

Overview

WideHive is a coherent batch-research skill, but its merge script has unsafe handling of result filenames and Excel-ready CSV output.

Install only if you are comfortable with a skill that can spawn many web-research workers and create workspace files. Use it on trusted target lists or sanitize slugs to simple names before merging, and treat merged.csv as untrusted when opening it in spreadsheet software.

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/merge_results.py:89
Finding
Spreadsheet Formula Injection in Generated CSV Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/merge_results.py`, lines 89-116 **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python row = {"slug": slug, "name": t.get("name", data.get("target", "")), "scenario": scenario} for k in fields: v = fd.get(k) if isinstance(v, (list, dict)): row[k] = json.dumps(v, ensure_ascii=False) else: row[k] = "" if v is None else v row["n_sources"] = len(data.get("sources") or []) rows.append(row) records.append(data) out_json = run / "merged.json" out_csv = run / "merged.csv" out_json.write_text( json.dumps({"scenario": scenario, "fields": fields, "records": records}, ensure_ascii=False, indent=2), encoding="utf-8") if rows: cols = ["slug", "name", "scenario"] + fields + ["n_sources"] with out_csv.open("w", newline="", encoding="utf-8-sig") as fh: w = csv.DictWriter(fh, fieldnames=cols) w.writeheader() for r in rows: w.writerow(r) ``` ### Technical Analysis The merger writes externally derived target names and worker-provided field values directly to `merged.csv`. Python's `csv` module performs CSV quoting but does not neutralize spreadsheet formulas. If a textual cell begins with a formula marker such as `=`, `+`, `-`, or `@`, spreadsheet applications may interpret the value as a formula rather than inert text. Leading whitespace, tab characters, or carriage returns can also be used to evade simplistic prefix checks in some spreadsheet clients. The documented workflow encourages users to open the resulting UTF-8-SIG CSV in Excel. Consequently, malicious content copied by a research worker from an untrusted web source can cross the data-to-executable-formula boundary when the report is opened. ### ...[truncated 1453 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Treat every textual CSV cell as untrusted, including `slug`, `name`, `scenario`, and all dynamically selected fields. 1. Add a centralized CSV-cell sanitization function. 2. Remove or reject leading control characters used to hide formula prefixes. 3. Prefix cells beginning with `=`, `+`, `-`, or `@` with a single quote so spreadsheet applications treat them as text. 4. Apply the function immediately before every value is passed to `csv.DictWriter`. 5. Preserve the original unsanitized values only in `merged.json`, with clear documentation that JSON consumers must treat them as untrusted. 6. Add tests for ordinary formulas and whitespace-, tab-, and carriage-return-prefixed variants. Example hardening: ```python DANGEROUS_FORMULA_PREFIXES = ("=", "+", "-", "@") def safe_csv_cell(value): if value is None: return "" text = str(value) inspected = text.lstrip(" \t\r\n") if inspected.startswith(DANGEROUS_FORMULA_PREFIXES): return "'" + text return text for row in rows: w.writerow({key: safe_csv_cell(value) for key, value in row.items()}) ``` If exact preservation of values is required, prefer a spreadsheet-generation library that can explicitly mark every untrusted cell as a string. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/merge_results.py:54
Finding
Path Traversal Through Unvalidated Target Slugs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/merge_results.py`, lines 54-66 **Vulnerability Type**: Path traversal and unintended local file read **Risk Level**: Medium ### Vulnerable Code ```python for t in targets: slug = t.get("slug", "") if not slug: defects.append({"slug": "?", "issues": ["target_without_slug"]}) continue f = result_dir / f"{slug}.json" if not f.exists(): missing.append(slug) continue try: data = json.loads(f.read_text(encoding="utf-8")) except Exception as e: defects.append({"slug": slug, "issues": [f"json_parse_error: {e}"]}) continue ``` ### Technical Analysis The `slug` value originates from `targets.json` and is used as part of a filesystem path without validation or containment checking: ```python f = result_dir / f"{slug}.json" ``` A slug containing parent-directory components, such as `../../private/report`, causes the resulting path to escape the intended `result/` directory. An absolute slug can also cause `pathlib` path joining to discard the preceding `result_dir` path. The `.json` suffix limits candidate files to names ending in `.json`, and the file must contain valid JSON to be successfully parsed. However, any readable JSON file reachable by the merger process may be loaded. If its top-level value is a compatible object, its contents are subsequently included in `merged.json`, while selected fields may also be copied into `merged.csv`. ### Attack Path 1. An attacker gains the ability to supply or modify the run's `targets.json`, or influences a target-generation process that does not sanitize slugs. 2. The attacker supplies a slug such as `../../sensitive/config` or an absolute path without the `.json` suffix. 3. The merger appends `.json` and resolves the path outside the intended `result/` directory. 4. The script checks that the external file exists and reads it ...[truncated 1103 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate slugs before using them as filenames and independently enforce path containment. 1. Permit only a conservative slug character set, such as ASCII letters, digits, underscores, and hyphens. 2. Reject slugs containing path separators, `.` path components, control characters, or absolute paths. 3. Resolve both `result_dir` and the candidate file path. 4. Verify that the candidate's parent is exactly the resolved result directory. 5. Reject duplicate slugs and non-object entries in `targets.json`. 6. Confirm that parsed result files contain a JSON object before calling `.get()`. 7. Consider limiting input file size to prevent memory-exhaustion attacks. Example hardening: ```python SLUG_RE = re.compile(r"^[A-Za-z0-9_-]+$") result_root = result_dir.resolve() for t in targets: slug = t.get("slug", "") if not isinstance(slug, str) or not SLUG_RE.fullmatch(slug): defects.append({"slug": str(slug), "issues": ["invalid_slug"]}) continue f = (result_root / f"{slug}.json").resolve() if f.parent != result_root: defects.append({"slug": slug, "issues": ["result_path_escape"]}) continue ``` After parsing, also validate the expected structure: ```python data = json.loads(f.read_text(encoding="utf-8")) if not isinstance(data, dict): defects.append({"slug": slug, "issues": ["result_must_be_json_object"]}) continue ``` ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill instructs use of file read/write and sub-agent orchestration, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, undeclared filesystem capabilities increase the chance of over-privileged execution, unsafe writes outside intended run directories, or accidental exposure/modification of workspace data by spawned workers.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger phrases are broad enough that the skill may activate for generic research requests, causing automatic fan-out, web fetching, and file creation when the user did not intend to invoke this high-capability workflow. Because the skill orchestrates many sub-agents and external fetches, accidental activation materially increases cost, data exposure surface, and operational risk.

Scope Creep

Low
Category
Excessive Agency
Content
```
You are a Wide Research single-object worker. Handle ONLY this one object;
do not expand scope.

Object: <name> (<url or unique identifier>)
Task:
Confidence
75% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Missing User Warnings

Low
Confidence
79% confidence
Finding
The script writes merged output files to merged.json and merged.csv, which can overwrite prior results in the run directory. Although the module docstring documents the outputs, the code itself provides no user-facing notice, confirmation, or logging at the point the write occurs.

Static analysis

No suspicious patterns detected.