Skip to content

fix(faucet): use get_user_id() instead of caller-supplied user_id - #7

Open
forumevi wants to merge 1 commit into
PsyProtocol:mainnet-betafrom
forumevi:fix/faucet-caller-id-griefing
Open

forumevi wants to merge 1 commit into
PsyProtocol:mainnet-betafrom
forumevi:fix/faucet-caller-id-griefing

Conversation

@forumevi

Copy link
Copy Markdown

Problem

faucet(user_id, amount) accepts user_id as an explicit argument, so any caller can pass an arbitrary user ID. This creates two issues:

Griefing: an attacker calls faucet(victim_id, max_amount) to exhaust the victim's entire rate-limit window. The victim receives the tokens but cannot claim from the faucet again for 120 blocks, without having requested anything.

Window manipulation: an attacker calls faucet(victim_id, 1) at an arbitrary block to reset the victim's window_start_block, shifting the 120-block window to a time the victim did not choose.

In both cases the attack costs only a transaction fee.

Fix

Replace the user_id parameter with get_user_id(), which reads the authenticated caller ID from the execution context. The invoke_deferred call is unchanged — user_id now always refers to the actual caller.

-    pub fn faucet(user_id: Felt, amount: Felt) {
+    pub fn faucet(amount: Felt) {
+        let user_id = get_user_id();

Testing

Existing behavior is preserved for the normal case (caller claims for themselves). The griefing path is no longer reachable because user_id is fixed to the transaction signer.

The faucet method accepted user_id as an explicit argument, letting any
caller pass an arbitrary user_id. This had two consequences:

1. Griefing: an attacker could call faucet(victim_id, max_amount) to
   exhaust the victim's rate-limit window without the victim's consent.
   The victim cannot claim from the faucet again until the 120-block
   window expires.

2. Front-running: a caller could manipulate another user's
   window_start_block by calling faucet(victim_id, 1) at any block,
   resetting the window to an arbitrary point.

Fix: replace the user_id parameter with get_user_id(), which reads the
authenticated caller ID from the execution context. The invoke_deferred
call is unchanged since user_id now always refers to the caller.
@forumevi

Copy link
Copy Markdown
Author

Note: the fix was verified by code review against the existing usage of get_user_id() in the same codebase (token/src/main.psy lines 279, 331, 415, 462) but was not compiled locally — the sandbox does not have a Rust toolchain. Happy to iterate if CI surfaces any issues.

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.

1 participant