Account allow/block/delete endpoints skip relay ownership check (cross-tenant IDOR) #9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
views_api.py:150-170(PUT /api/v1/account) andviews_api.py:173-187(DELETE /api/v1/account/{relay_id}/{pubkey}) carrydependencies=[Depends(require_admin_key)]but never verify that the caller's wallet ownsrelay_id.api_create_or_update_accountdoes not even receive theWalletTypeInfo; it takesdata.relay_idfrom the body and callsget_account/create_account/update_accounton the global accounts table keyed by(relay_id, pubkey).api_delete_accountis the same.Compare
api_get_accountsatviews_api.py:197-203, which doesget_relay(wallet.wallet.user, relay_id)and 404s.Impact: any LNbits user with any admin key can, on a relay they do not own: set
allowed=truefor their own pubkey and bypass pay-to-join (NostrAccount.can_joinatmodels.py:31-33); setblocked=truefor arbitrary pubkeys (enforced atrelay/event_validator.py:87-91andrelay/client_connection.py:298-307), censoring other operators' users; delete other operators' account rows.Fix direction: thread
wallet: WalletTypeInfo = Depends(require_admin_key)into both handlers and gate onget_relay(wallet.wallet.user, relay_id)exactly asapi_get_accountsdoes, before any mutation.Found during reforge run #1 (sandbox nostrrelay#3).