Reproduction steps:
- Use a clean RailCall Station v0.78 workspace.
- Store this engine spec as an installed workflow:
{
"id": "cap-bypass",
"capabilities": {
"providers": ["safe_provider"],
"allow_irreversible": false
},
"nodes": [
{
"id": "pay",
"type": "effect",
"action_id": "fakepay_charge",
"args": {"amount_cents": 1}
}
]
}
- Resolve
fakepay_chargeto a harmless local stub withaction_class="external_send"; itsapply()only writes an in-memory marker. - Call the real
routes.dispatch_workflow._handle_dag_run()withdry_run=false, live execution capability enabled, and Team gateproceed. - Control case: submit the same workflow to
workflow_mcp.stage_workflow().
Expected:
providersis an allowlist. A provider not in the list must be refused.allow_irreversible:falsemust refuse anexternal_sendaction.- Direct DAG execution must enforce the same declared scope as the workflow staging path.
Actual:
direct route outcome = "COMPLETED"
effect marker = [1]
plan systems_touched= ["fakepay"]
plan irreversible = ["pay:fakepay_charge"]
Control result:
workflow_mcp.stage_workflow() -> ok=false
error -> "capability exceeded: workflow touches ['fakepay'] but its declared providers are ['safe_provider']"
The MCP control refused before creating a run token. The direct DAG route executed the same out-of-scope effect.
Root cause:
workbench/workflow_mcp.py:137-175implements the declared capability checks forproviders,egress_hosts,max_spend_cents, andallow_irreversible.workbench/workflow_mcp.py:187-205invokes those checks during staging.workbench/routes/dispatch_workflow.py:681-725never calls_validate_wf()or_check_capabilities()before plan pin/run.workbench/workflow_engine.py:681-686enforces only the runtime spend field; it does not enforce provider, egress, or irreversible scope.
Impact:
A workflow can execute a provider and irreversible action outside the capability scope it declares. The harness used no network or financial provider; it proved the out-of-scope execution boundary was reached.
Suggested fix:
Apply the same capability validation to direct DAG runs before plan pinning and execution, or move capability enforcement into the shared engine so every execution surface receives identical scope checks.