Reproduction steps:
- Run Station v0.97 with a synthetic workflow containing one HTTP POST node:
capabilities.max_spend_cents = 0
node.type = "http"
request.method = "POST"
request.url = "https://example.com/pay"
request.body = {"amount_cents": 999, "currency": "usd"}
- Allow the destination in the test policy and use an HTTP mock so no real network or financial write occurs.
- Create the workflow plan and inspect the spend estimate.
- Apply the plan through the normal workflow execution path with the mock enabled.
- Repeat the same run twice to rule out a one-off harness result.
- Control case: replace the HTTP node with a normal spend-bearing effect node using amount_cents=1 and keep max_spend_cents=0.
Expected:
Any spend-bearing action must either be included in the spend-cap calculation or fail closed as an unpriced/unknown-spend action. With max_spend_cents=0, the HTTP POST must not reach its external-effect executor.
Actual:
The HTTP branch contributes zero estimated spend. The plan is staged with spend=0, and execution reaches the HTTP executor despite max_spend_cents=0. The HTTP mock is called and the run completes. Repeating the run produces the same result. The control effect node is blocked and rolls back with SpendCapExceeded, confirming that the harness and cap enforcement are active for the effect path.
Station version (railcall version):
station-v0.97
Affected code path:workflow_engine.py HTTP planning branch and HTTP execution spend-cap checks; the spend estimate/credit logic is present for kind == "effect" but not for kind == "http". HTTP mutating requests are classified as external_send by workflow_http.py.
Security / integrity impact:
A workflow can declare a zero or finite spend ceiling while a spend-bearing HTTP POST remains outside the ceiling and reaches the external-effect path. This weakens a financial/governance control at the boundary between workflow planning and execution.
Evidence:
- HTTP fixture:
stage=True,stage_spend=0. - HTTP fixture apply:
apply_outcome=COMPLETED,apply_ok=True,mock_calls=1. - Repeated direct run:
plan_spend=0,outcome=COMPLETED,calls=1. - Control effect with cap 0:
outcome=ROLLED_BACK, no apply,SpendCapExceeded. - No real network request or financial write was performed.
Suggested fix:
Ensure HTTP nodes that can carry spend-bearing effects are represented in the plan's spend estimate and pre-execution cap check. If the platform cannot derive a trustworthy amount from an HTTP request, fail closed or require an explicit, signed spend estimate instead of treating the action as zero spend.
AFFECTED VERSION:
station-v0.97