OpenZeppelin / OpenZeppelin/compact-contracts

L-04: Zero-Value Transfers Can Be Used To Deny Service To Genuine Credits

Open
#802 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

2-low audit
Dominant language
TypeScript
Stars
55
Forks
29
Avg merge
5d 7h
Merged PRs (30d)
25

Description

L-05 Zero-Value Transfers Can Be Used To Deny Service To Genuine Credits

Severity: Low

Source: Midnight Foundation #02 — OpenZeppelin Compact Contracts Audit, Release 0.3.0-alpha.1 (2026-08-18)


Delivering value reads the recipient's memo list, takes its current length as a nonce, folds that nonce into the randomness for the balance update and for the memo, rewrites that recipient's pending ciphertext, and appends to the same list. The length a credit reads is therefore part of what its transaction records having read, and appending the memo changes that same length. Every credit to one account therefore depends on a value it goes on to alter. Two credits prepared against the same view of this value cannot both remain valid, and the module records this as a documented limitation, acceptable for its first target use case of tokenized deposits.

The note describes a concurrency property where two ordinary payments arrive together and one needs a retry. The same mechanism is also available deliberately and at almost no cost. Reaching the credit path requires only a transfer, the per-operation check bounds a value from above and not from below, and a debit compares the caller's balance against the amount requested, a comparison that a zero amount satisfies for any registered account including one that holds the encrypted zero written at registration. A party wanting to disrupt a particular account can therefore send it repeated zero-valued transfers, each invalidating whatever genuine credit was prepared against the previous state, for the price of fees and no capital at all. Any credit has the same effect, since the conflict follows from the read and the append rather than from the amount, but a non-zero transfer pays value to the target and is limited by the sender's balance, whereas the zero-valued form is free and unbounded. The recipient has no response available, since the contention is on the state every incoming credit must touch, and clearing the memo list neither prevents nor slows it.

The use case named as making the limitation acceptable is also the one in which it is most impactful. A tokenized deposit address is published so that others may pay into it, is reused, and is expected to remain reachable, which makes it both an easy target and a costly one to have blocked. The disclosure and the exposure therefore point in opposite directions, and the module does not say that the conflict is reachable on demand by anyone rather than only by coincidence.

Consider giving each incoming credit its own key, so that concurrent payments to one recipient write to distinct locations and are combined when the recipient next sweeps, which removes the shared state that forces them to serialize. Consider at least rejecting zero-valued transfers, which does not address contention between genuine payments but does remove the free and unlimited form of it, and stating in the concurrency note that the conflict can be produced deliberately, so that a deployment relying on inbound liveness evaluates it as an availability property rather than as an occasional retry.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in contracts/src/token/ConfidentialFungibleToken.compact at the recipient memo-list handling, transfer checks, and debit path linked in the report. Read the concurrency limitation near the documented tokenized-deposit use case before choosing a mitigation. The issue leaves the design open; completion requires an agreed approach, validation that zero-value transfers cannot cheaply invalidate credits, and updated documentation of the limitation.

Written by the indexing model from the issue text.

Assessment

Domain
blockchain, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.