Back to skill

Security audit

Agentic Workflow Automation

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to be a legitimate workflow blueprint generator, but its script can create or overwrite files even when dry-run says it will not.

Review this skill before installing. It is not showing malicious behavior, but only use it where generated files are directed to a safe output location, do not rely on --dry-run to avoid file changes, and avoid opening CSV exports from untrusted workflow inputs until the publisher fixes dry-run handling, overwrite controls, and CSV formula sanitization.

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/generate_workflow_blueprint.py:104
Finding
Dry-Run Mode Still Creates Directories and Overwrites Files## Vulnerability Details **File Location**: `scripts/generate_workflow_blueprint.py`, lines 17, 31-54, and 104 **Vulnerability Type**: Violation of dry-run semantics and unrestricted file overwrite **Risk Level**: Medium **Vulnerable code:** ```python def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Generate a workflow automation blueprint.") parser.add_argument("--input", required=False, help="Path to JSON input.") parser.add_argument("--output", required=True, help="Path to output artifact.") parser.add_argument("--format", choices=["json", "md", "csv"], default="json") parser.add_argument("--dry-run", action="store_true", help="Run without side effects.") return parser.parse_args() ``` ```python def render(result: dict, output_path: Path, fmt: str) -> None: output_path.parent.mkdir(parents=True, exist_ok=True) if fmt == "json": output_path.write_text(json.dumps(result, indent=2), encoding="utf-8") return if fmt == "md": details = result["details"] lines = [ f"# {result['summary']}", "", f"- status: {result['status']}", f"- workflow_name: {details['workflow_name']}", f"- trigger: {details['trigger']}", "", "## Steps", ] for step in details["steps"]: lines.append(f"- {step['order']}. {step['name']} ({step['type']})") output_path.write_text("\n".join(lines) + "\n", encoding="utf-8") return with output_path.open("w", newline="", encoding="utf-8") as handle: writer = csv.DictWriter(handle, fieldnames=["order", "name", "type", "on_failure"]) writer.writeheader() writer.writerows(result["details"]["steps"]) ``` ```python render(result, Path(args.output), args.format) ``` ### Technical Analysis The `--dry-run` o ...[truncated 1720 chars]
Remediation
## Remediation Suggestions - Enforce dry-run behavior before invoking the rendering function: ```python if args.dry_run: print(json.dumps(result, indent=2)) return 0 render(result, validated_output_path, args.format) ``` - Resolve the output path and require it to remain within a dedicated output directory or approved workspace. - Reject absolute paths and parent-directory traversal when arbitrary destinations are unnecessary. - Detect and reject symbolic-link targets where symlink following is not intended. - Avoid silent truncation. Use exclusive creation mode for new artifacts or require an explicit `--force` option before overwriting an existing file. - Add automated tests confirming that `--dry-run` neither creates directories nor creates, modifies, or truncates files.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_workflow_blueprint.py:51
Finding
Spreadsheet Formula Injection in CSV Export## Vulnerability Details **File Location**: `scripts/generate_workflow_blueprint.py`, lines 51-54 and 73-83 **Vulnerability Type**: CSV formula injection **Risk Level**: Medium **Vulnerable code:** ```python with output_path.open("w", newline="", encoding="utf-8") as handle: writer = csv.DictWriter(handle, fieldnames=["order", "name", "type", "on_failure"]) writer.writeheader() writer.writerows(result["details"]["steps"]) ``` ```python normalized_steps = [] for idx, step in enumerate(steps, start=1): normalized_steps.append( { "order": idx, "name": str(step.get("name", f"step-{idx}")), "type": str(step.get("type", "task")), "on_failure": str(step.get("on_failure", "stop")), } ) ``` ### Technical Analysis The `name`, `type`, and `on_failure` fields originate in the input JSON and are converted to strings without neutralizing spreadsheet formula prefixes. They are then written directly into CSV cells. CSV quoting only preserves field boundaries; it does not prevent spreadsheet software from interpreting cells beginning with characters such as `=`, `+`, `-`, or `@` as formulas. Leading tabs or carriage returns may also be used to bypass simplistic prefix checks in some import workflows. For example, an attacker-controlled step name could be: ```text =HYPERLINK("https://attacker.invalid/collect","Open workflow") ``` When the exported file is opened in a spreadsheet application, the value may be interpreted as a formula rather than inert text. The precise behavior and whether external content is accessed depend on the spreadsheet product, version, and security configuration. ### Attack Path 1. An attacker supplies workflow JSON containing a formula-prefixed value in `name`, `type`, or `on_failure`. 2. The script normalizes the value with `str()` but does ...[truncated 1020 chars]
Remediation
## Remediation Suggestions - Neutralize untrusted CSV cells before passing them to `csv.DictWriter`. - Treat values beginning with `=`, `+`, `-`, `@`, tab, or carriage return as potentially dangerous. - Prefix dangerous values with an apostrophe or use another encoding strategy appropriate for the intended spreadsheet consumers. For example: ```python def sanitize_csv_cell(value: object) -> str: text = str(value) if text.startswith(("=", "+", "-", "@", "\t", "\r")): return "'" + text return text ``` - Apply the sanitizer to every user-controlled CSV field, including `name`, `type`, and `on_failure`. - Preserve unsanitized values for JSON or Markdown only if downstream consumers treat those formats as data rather than executable markup. - Document that workflow fields are untrusted and add tests covering all recognized formula prefixes, including leading control characters.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill explicitly instructs use of a bundled script and reference files, which implies file read/write behavior, but it does not declare any tool scope or permission boundaries. This creates an authorization ambiguity where an agent may access local files more broadly than intended, increasing the risk of unintended file exposure or modification when the skill is invoked.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The description uses broad, capability-oriented language such as designing, orchestrating, automating, and generating production-ready artifacts without clear invocation boundaries or preconditions. In agent environments, this can cause overbroad routing or autonomous use in contexts the user did not intend, potentially leading to unnecessary file operations or workflow generation based on ambiguous prompts.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The script advertises `--dry-run` as having no side effects, but `main()` still calls `render()` unconditionally, which creates directories and writes the output file. In automation contexts, operators may rely on dry-run semantics for safe validation, so this mismatch can cause unintended filesystem modification, artifact creation, and downstream pipeline triggering.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Even when `--dry-run` is specified, the code writes the artifact to the user-supplied path without any warning or confirmation. In an agentic workflow automation skill, that is more dangerous because other tools or jobs may watch those paths and treat the artifact as a real handoff, causing unintended execution or state changes despite the user's expectation of a non-mutating test run.

Static analysis

No suspicious patterns detected.