Back to skill

Security audit

Workflow Orchestrator

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent workflow runner, but its documented safety controls for conditions and timeouts can fail in ways that may run or hang consequential agent steps.

Review carefully before installing or using with real agents that send messages, publish content, deploy, or modify data. Treat workflow definitions and registered executors as trusted code, and do not rely on the current condition or timeout behavior as a safety boundary without fixing it first.

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/orchestrator.py:154
Finding

Workflow Conditions Fail Open and Permit Guarded Steps to Execute

Content
View full analysis
bool: """Evaluate a simple condition like '$.step.status == "completed"'.""" if not condition: return True # Simple evaluator — production would use JSONPath try: if "==" in condition: path, expected = condition.split("==", 1) path = path.strip().lstrip("$.").split(".") value = context for key in path: value = value.get(key, {}) if isinstance(value, dict) else {} return str(value).strip() == expected.strip().strip('"') except Exception: pass return True ``` ### Technical Analysis The condition evaluator defaults to `True` whenever a condition cannot be evaluated. This includes: - Conditions using unsupported operators or syntax. - Conditions without the `==` operator. - Conditions that trigger an exception. - Unexpected condition types or malformed path expressions. This is a fail-open design. A workflow condition commonly acts as a security or safety gate that controls whether a consequential agent action may run. When parsing or evaluation fails, execution should be denied or the workflow should be rejected. Instead, the current implementation treats invalid conditions as satisfied. The behavior also differs from the documented JSONPath condition support. The implementation only recognizes a limited equality expression and silently permits execution for unsupported expressions. ### Attack Path 1. An attacker or untrusted workflow author defines a step that performs a consequential action, such as publishing data, sending a notification, deploying an artifact, or deleting a resource. 2. The attacker supplies a malformed or unsupported co ...[truncated 823 chars]
Remediation
View remediation
bool: if not condition: return True if not isinstance(condition, str) or "==" not in condition: raise ValueError("Unsupported workflow condition") path, expected = condition.split("==", 1) keys = path.strip().removeprefix("$.").split(".") value = context for key in keys: if not isinstance(value, dict) or key not in value: return False value = value[key] return str(value).strip() == expected.strip().strip('"') ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/orchestrator.py:126
Finding

Step Timeout Configuration Is Not Enforced

Content
View full analysis
StepResult: """Execute a single step with retry and timeout.""" executor = self._agent_executor.get(step.agent) if not executor: # Mock executor for testing executor = lambda action, params, ctx: {"result": f"mock_{action}"} for attempt in range(1, step.retry + 2): start = time.time() try: output = executor(step.action, step.params, context) duration = time.time() - start result = StepResult( step_name=step.name, status=StepStatus.COMPLETED, output=output, duration_sec=round(duration, 2), attempts=attempt, ) with self._lock: self.step_outputs[step.name] = output return result except Exception as e: duration = time.time() - start if attempt <= step.retry: time.sleep(min(2 ** attempt, 30)) # exponential backoff continue # Final failure if step.on_failure == "skip": return StepResult(step.name, StepStatus.SKIPPED, error=str(e), duration_sec=duration, attempts=attempt) elif step.on_failure == "fallback" and step.fallback_step: return StepResult(step.name, StepStatus.FAILED, error=str(e), duration_sec=duration, attempts=attempt) else: ...[truncated 1867 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/orchestrator.py:67
Finding

Missing Workflow Dependencies Cause an Unhandled Validation Exception

Content
View full analysis
list[str]: """Check for cycles and missing dependencies.""" errors = [] for name, step in self.steps.items(): for dep in step.depends_on: if dep not in self.steps: errors.append(f"Step '{name}' depends on missing step '{dep}'") if dep == name: errors.append(f"Step '{name}' depends on itself") # Cycle detection via DFS visited, in_stack = set(), set() def dfs(node): if node in in_stack: return True if node in visited: return False visited.add(node) in_stack.add(node) for dep in self.steps[node].depends_on: if dfs(dep): errors.append(f"Cycle detected involving step '{node}'") return True in_stack.remove(node) return False for name in self.steps: dfs(name) return errors ``` ### Technical Analysis The first validation loop correctly detects dependency names that are absent from `self.steps`, but validation continues into cycle detection. The depth-first search recursively calls `dfs(dep)` for every dependency without checking whether the dependency exists. When `dfs()` receives the missing dependency name, this statement raises `KeyError`: ```python for dep in self.steps[node].depends_on: ``` As a result, `Workflow.validate()` does not return its collected validation errors. Because `Runner.execute()` calls `workflow.validate()` without exception handling, malformed workflow input can terminate execution rather than producing the intended `{"status": "invalid", "errors": ...}` response. ### Attack Path 1. An attacker or untrusted caller submits a workflow containing a dependency on a nonexisten ...[truncated 696 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This code executes arbitrary registered agent functions across workflow steps, and the demo includes network-oriented and publishing actions such as 'fetch' and 'send'. There is no confirmation prompt, user-facing logging, or warning comment/docstring indicating that execution may contact external services or publish data, which leaves safety-relevant behavior undisclosed in this code file.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.