Skip to content

fix: add role and ownership guards to all order-lifecycle handlers#558

Open
Ridanshi wants to merge 1 commit into
Shruti070107:mainfrom
Ridanshi:fix/issue-541-receipt-authorization
Open

fix: add role and ownership guards to all order-lifecycle handlers#558
Ridanshi wants to merge 1 commit into
Shruti070107:mainfrom
Ridanshi:fix/issue-541-receipt-authorization

Conversation

@Ridanshi

@Ridanshi Ridanshi commented Jun 1, 2026

Copy link
Copy Markdown

Closes #541

Issue confirmed

Five globally accessible order-lifecycle functions had no authorization checks. Any authenticated session — regardless of role — could call them directly from the browser console to trigger unauthorized state changes and reward issuance.

Handlers fixed

confirmPlantReceipt (primary issue)

window.confirmPlantReceipt is a global function with no role or ownership check. Any user could call confirmPlantReceipt('any-order-id') to complete any order in at_plant state and mint $RGX reward tokens for the provider's account.

Two guards are now the first checks after the idempotency guard — before any processing, any mutation, any reward calculation:

if (SESSION.role !== 'plant')     '⚠ Unauthorized: only a plant account can confirm receipts.'
if (o.plantId !== SESSION.id)     '⚠ Unauthorized: this order is not assigned to your plant.'

The confirm() dialog is also moved before all mutations (so cancellation is a zero-side-effect no-op), and earnedTokens is declared as let outside the if (providerAcc) block to fix a ReferenceError that fired when the provider account was absent.

riderAccept

No role check and no order-status guard allowed any user to overwrite any order — including completed ones — claiming the riderId. Added:

  • SESSION.role !== 'rider' guard
  • o.status !== 'requested' guard (prevents reassigning already-in-flight orders)

riderUpdate

No role or rider-ownership check. Added:

  • SESSION.role !== 'rider' guard
  • o.riderId !== SESSION.id guard

confirmPickup

Same rider-ownership gap as riderUpdate, plus a missing null check on the order object. Added null safety and both guards.

cancelOrder

No role or ownership check. Any user could cancel any dispatch. Added:

  • SESSION.role !== 'provider' guard
  • o.providerId !== SESSION.id guard

Test results

Results: 39 passed, 0 failed

Test 20 (regression) directly proves the exploit: a plant session for plant-attacker cannot complete an order assigned to plant-correct, no tokens are issued, and the provider's balance is unchanged.

Five globally accessible order-lifecycle functions had no authorization
checks.  Any authenticated session — regardless of role or account — could
call them from the browser console to trigger unauthorized state changes
and reward issuance.

confirmPlantReceipt (primary issue Shruti070107#541)
  No role check and no plant-ownership check meant any user could:
    - call confirmPlantReceipt(orderId) on any order in at_plant state
    - complete the order and mint $RGX reward tokens for the provider
    - do so repeatedly to inflate balances
  Two guards are now enforced before any other processing:
    if (SESSION.role !== 'plant') → reject
    if (o.plantId !== SESSION.id) → reject
  Also incorporated alongside: the confirm() dialog is moved before all
  mutations so cancellation is a guaranteed no-op; earnedTokens is
  declared as let outside the if(providerAcc) block to fix a ReferenceError
  that fired when the provider account was absent.

riderAccept
  No role check and no order-status guard allowed any user to overwrite
  any order — including already-completed ones — setting status to
  'assigned' and claiming the riderId.  Guards added:
    if (SESSION.role !== 'rider') → reject
    if (o.status !== 'requested') → reject (order unavailable)

riderUpdate
  No role check and no rider-ownership check allowed any authenticated
  user to advance any order's delivery status.  Guards added:
    if (SESSION.role !== 'rider') → reject
    if (o.riderId !== SESSION.id) → reject

confirmPickup
  Same rider-ownership gap as riderUpdate, plus a missing null check on
  the order object.  Guards added:
    if (!o) → reject (null safety)
    if (SESSION.role !== 'rider') → reject
    if (o.riderId !== SESSION.id) → reject

cancelOrder
  No role check and no ownership check allowed any user to cancel any
  dispatch.  Guards added:
    if (SESSION.role !== 'provider') → reject
    if (o.providerId !== SESSION.id) → reject

Added scripts/test-order-authorization.mjs (39 assertions) covering
all five handlers: role blocked, ownership blocked, correct-session
succeeds, rewards issued only after authorization, cancellation leaves
no side effects, and a regression test demonstrating that a plant
account cannot complete an order assigned to a different plant.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

confirmPlantReceipt allows unauthorized completion of plant receipts because order ownership is not validated

1 participant