Back to skill

Security audit

Pipelinegate

Security checks for vulnerabilities and agentic risk

Overview

PipelineGate is a disclosed local pipeline server for security checks, with no evidence of hidden exfiltration or persistence, but it should be kept local and used with bounded inputs.

Install only if you intend to run a local PipelineGate API. Keep it bound to localhost or place authentication and limits in front of it, avoid sending secrets in pipeline payloads, and pin/review dependencies for production use.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
pipelinegate/executor.py:137
Finding
Unauthenticated Environment and Executable Reconnaissance## Vulnerability Details **File Location**: `pipelinegate/executor.py:137-149`; exposed through `pipelinegate/app.py:24-49` **Vulnerability Type**: Missing authorization for host environment discovery **Risk Level**: Medium ### Vulnerable Code ```python def exec_check_env(inp: dict) -> dict: req_env = inp.get("required_env", []) req_bins = inp.get("required_bins", []) present_env = [v for v in req_env if os.environ.get(v) is not None] missing_env = [v for v in req_env if os.environ.get(v) is None] present_bins = [b for b in req_bins if shutil.which(b) is not None] missing_bins = [b for b in req_bins if shutil.which(b) is None] return { "ready": len(missing_env) == 0 and len(missing_bins) == 0, "present_env": present_env, "missing_env": missing_env, "present_bins": present_bins, "missing_bins": missing_bins, } ``` The operation is exposed through an endpoint with no authentication or authorization: ```python @app.post("/v1/run", response_model=PipelineResponse) async def run_pipeline(request: PipelineRequest) -> PipelineResponse: """Execute a multi-step pipeline.""" results: list[StepResult] = [] completed = 0 overall_success = True for step in request.steps: success, output, error = execute_step(step.tool, step.input) results.append(StepResult( tool=step.tool, success=success, output=output, error=error, )) ``` ### Technical Analysis The `check-env` tool accepts arbitrary environment-variable and executable names from a request. It tests those names against the server's process environment and executable search path, then returns the results directly. The application does not apply authentication, authorization, an allowlist, or a trust-boundary check before invoking this functionality. Consequently, any client capable of reaching the ...[truncated 1461 chars]
Remediation
## Remediation Suggestions 1. Require authenticated access to `/v1/run`, and authorize callers separately for tools that inspect server state. 2. Bind the service to the loopback interface by default unless remote access is explicitly required and protected. 3. Replace arbitrary client-supplied environment and binary names with a server-side allowlist. 4. Permit checks only for dependencies explicitly declared by the installed Skill or approved configuration. 5. Consider returning only a general readiness result rather than identifying every present environment variable and executable. 6. Apply request rate limits and audit repeated enumeration attempts. 7. Run the service with a minimal environment and restricted executable search path.

T09 · Insecure Skill Coding Practices

Error
Location
pipelinegate/executor.py:103
Finding
Resource Exhaustion Through Unbounded Pipeline Inputs and Synchronous Processing## Vulnerability Details **File Location**: `pipelinegate/models.py:9-19`, `pipelinegate/executor.py:103-134`, and `pipelinegate/app.py:24-49` **Vulnerability Type**: Uncontrolled resource consumption and application-layer denial of service **Risk Level**: High ### Vulnerable Code The request model limits the number of steps but does not constrain the size, depth, or complexity of each step's input: ```python class PipelineStep(BaseModel): model_config = ConfigDict(extra="forbid") tool: str = Field(..., description="Tool name (scan-text, scan-skill, check-scope, validate, diff, check-env, convert).") input: dict[str, Any] = Field(..., description="Input payload for the tool.") class PipelineRequest(BaseModel): model_config = ConfigDict(extra="forbid") steps: list[PipelineStep] = Field(..., min_length=1, max_length=20, description="Pipeline steps to execute.") stop_on_error: bool = Field(default=True, description="Stop pipeline on first error.") ``` Schema validation can traverse complex attacker-controlled schemas and payloads and retain every validation error: ```python def exec_validate(inp: dict) -> dict: schema = inp["json_schema"] payload = inp["payload"] errors = [] try: validator_cls = jsonschema.validators.validator_for(schema) validator_cls.check_schema(schema) except jsonschema.SchemaError as e: return {"valid": False, "error_count": 1, "errors": [{"path": "$schema", "message": str(e.message)}]} validator = jsonschema.Draft202012Validator(schema) for err in sorted(validator.iter_errors(payload), key=lambda e: list(e.path)): path = ".".join(str(p) for p in err.absolute_path) or "$" errors.append({"path": path, "message": err.message}) return {"valid": len(errors) == 0, "error_count": len(errors), "errors": errors} ``` Text comparison performs potentially expensive matching and constr ...[truncated 3264 chars]
Remediation
## Remediation Suggestions 1. Configure a strict maximum HTTP request-body size at the reverse proxy and application layers. 2. Replace the generic input dictionary with tool-specific Pydantic models that enforce maximum string lengths, collection sizes, nesting depth, and allowed values. 3. Set conservative limits for diff line count, total text size, schema size, payload size, and YAML/JSON document size. 4. Stop JSON Schema validation after a bounded number of errors instead of collecting and sorting every error. 5. Cap response sizes and truncate large difference or validation result collections with an explicit truncation indicator. 6. Apply per-client rate limits, concurrency limits, request deadlines, and worker resource quotas. 7. Offload CPU-intensive operations to bounded worker threads or, preferably, isolated worker processes with memory and execution-time limits. 8. Reject excessive YAML alias expansion and deeply nested documents even when using `safe_load`. 9. Require authentication to reduce anonymous resource abuse and monitor repeated oversized or expensive requests.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:4
Finding
Unpinned and Incompletely Declared Runtime Dependencies## Vulnerability Details **File Location**: `SKILL.md:4`; related imports in `pipelinegate/executor.py:10-18` **Vulnerability Type**: Non-reproducible and incomplete software supply-chain configuration **Risk Level**: Medium ### Vulnerable Code The installation metadata specifies mutable package names without versions or integrity hashes: ```yaml metadata: {"openclaw":{"emoji":"⛓️","requires":{"bins":["python"]},"install":[{"id":"pip","kind":"uv","packages":["fastapi","uvicorn","pydantic","pyyaml","jsonschema"]}]}} ``` The application additionally imports undeclared ambient product modules: ```python from products.promptguard.promptguard.detectors import scan as injection_scan from products.promptguard.promptguard.detectors import TOTAL_PATTERNS as INJECTION_TOTAL from products.skillscan.skillscan.detectors import scan as skillscan_scan from products.skillscan.skillscan.detectors import TOTAL_PATTERNS as SCAN_TOTAL from products.scopecheck.scopecheck.extractors import ( extract_cli_tools, extract_declared, extract_env_vars, extract_filesystem_paths, extract_network_urls, ) ``` ### Technical Analysis The installer resolves `fastapi`, `uvicorn`, `pydantic`, `pyyaml`, and `jsonschema` without exact version constraints or cryptographic hashes. As package indexes change, separate installations can retrieve different code despite using the same reviewed Skill source. This weakens reproducibility and increases exposure to compromised upstream releases, unexpected major-version changes, or dependency-resolution changes. The audit did not identify a known malicious dependency in the supplied project, so the finding concerns unsafe dependency management rather than confirmed malicious package inclusion. The imports under `products.*` are not represented in the installation metadata. Their provenance and expected versions therefore depend on undocumented code already present in the runtime env ...[truncated 1269 chars]
Remediation
## Remediation Suggestions 1. Pin every direct dependency to an exact, reviewed version. 2. Generate and commit a lockfile covering direct and transitive dependencies. 3. Require cryptographic hashes for downloaded artifacts where supported. 4. Declare the `products.promptguard`, `products.skillscan`, and `products.scopecheck` components explicitly, including their source and reviewed versions. 5. Install packages only from controlled or allowlisted registries and disable untrusted extra indexes. 6. Use automated vulnerability and provenance scanning for the locked dependency set. 7. Rebuild dependencies periodically in a controlled environment, review updates, and test them before changing the lockfile. 8. Run the service under a least-privileged account so that a compromised dependency has limited access.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior promises ordered multi-step execution with stop-on-error/continue-on-failure semantics, but the finding indicates the implementation does not actually enforce that contract and may operate as a single-step dispatcher. Security tooling that behaves differently from its declared design can cause users or downstream agents to rely on checks that never occur, creating silent security gaps and policy bypasses.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill exposes server functionality that can process pipeline requests and references environment-related capability (`check-env`), but it declares no explicit tool scope or permission boundaries. In an agent ecosystem, missing scope declarations can allow broader-than-expected access to host resources or execution pathways, increasing the chance of misuse or unsafe composition with other tools.

External Transmission

Medium
Category
Data Exfiltration
Content
## Run a security pipeline

```bash
curl -s -X POST http://localhost:8011/v1/run \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
## Run a security pipeline

```bash
curl -s -X POST http://localhost:8011/v1/run \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The registered description for the "convert" step says it can "Convert between JSON/YAML/TOML," but the implementation accepts only "json" and "yaml" input/output formats and returns an unsupported-format error otherwise. This is an active contradiction between inline documentation/metadata and actual behavior.

Static analysis

No suspicious patterns detected.