Skip to content

sec(ri-exchange): direct execute paths run an irreversible exchange with no approval and no four-eyes check #517

Closed

Description

@cristim

Summary

Both direct-execute RI exchange endpoints run an irreversible exchange for a single user holding execute:ri-exchange. There is no approval step and no four-eyes check. Merged #501 added four-eyes only to the approve path, so manual exchanges never see it.

Location (origin/main 496d9d7)

  • internal/api/handler_ri_exchange.go:1805 executeExchange (AWS)
  • internal/api/handler_ri_exchange.go:1173 executeAzureExchange (Azure)
  • Four-eyes only applies at internal/api/handler_ri_exchange.go:2390 requireDifferentRIExchangeApprover, called from the approve path.

Failure scenario

With RequireDifferentApprover enabled, one user with execute:ri-exchange quotes and executes an exchange that commits money in a single request. No second person is involved. This bypasses the dual-control policy that purchases and approved exchanges follow.

Context

Found in the #501 review. Related: #82 (no audit row for direct executes), #145, #221 (closed, approve path), #233.

Acceptance

When four-eyes is enabled, a direct exchange execute either requires a second approver or is refused, covered by a test for both AWS and Azure.

Activity

  1. cristim commented on Oct 8, 2026

    @cristim
    MemberAuthor

    Merged: PR #673, squash commit 8680d5b (reviewed head 2aa8f1d). Both direct-execute endpoints (AWS executeExchange, Azure executeAzureExchange) now return 403 while 4-eyes mode is on, after permission/scope/constraints and before any quote, exchange or idempotency claim; a global-config lookup failure fails closed.

    Verified: independent review (APPROVE at the exact head, with a no-op-gate mutation showing both new tests fail without the fix); full non-race go test ./internal/api pass; PR CI green. Mock-based; no live AWS/Azure calls. Race suite not run locally (disk hold).

    Not covered (tracked in #679): scheduler auto mode still executes unattended under 4-eyes; nil-creator exchange rows remain approvable (#233); two minor test gaps. Interactive one-shot exchanges are refused while 4-eyes is on (no second-approver flow for them).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions