OpenZeppelin / OpenZeppelin/compact-contracts
L-06: clearMemos Does Not Return the Authenticated Identifier
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 55
- Forks
- 29
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 25
Description
L-03 clearMemos Does Not Return the Authenticated Identifier
Severity: Low
Source: Midnight Foundation #02 — OpenZeppelin Compact Contracts Audit, Release 0.3.0-alpha.1 (2026-08-18)
The module makes caller-side gating sound by having each caller-authenticating circuit return the identifier it authenticated. The header enumerates them as register, _burn, transfer, _move, approve, transferFrom, sweep and _burnFrom. clearMemos authenticates a caller in exactly the same way, deriving the account from wit_ConfidentialTokenSK, but returns [] and is absent from that list.
The contrast with sweep is direct: both are maintenance circuits that authenticate the identity secret alone and act only on the caller's own state, yet sweep returns the identifier and clearMemos does not. However, that return value is what lets a wrapper gate without a witness of its own. A wrapper layering an allowlist or blocklist over the module needs the identifier the module actually authenticated, because as the header states, "a separate witness call in the wrapper could return a different secret than the one this module authenticates with, letting a frozen account slip a clean id past the gate". A witness is offchain code that may answer differently on two calls within one circuit, so any identifier a wrapper derives itself is unconstrained against the one the module used. The returned value is therefore the only sound source, and clearMemos supplies none. Furthermmore, allowing clearMemos to bypass allowlist/ blocklist integrations is not ideal given its destructive behavior. Assume an edgecase scenario where a secret key is leaked and that account is blocklisted, the accessible clearMemos circuit can provide a window to the attacker to clear the memos before the owner/wallet sees and thus, permanently blocking the funds.
Consider returning the authenticated account identifier from clearMemos as the other caller-authenticating circuits do, and adding it to the header's enumeration so the list matches the code, which restores the guarantee for the one entry point currently outside it.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in contracts/src/token/ConfidentialFungibleToken.compact by reading the clearMemos circuit and the header enumeration of caller-authenticating circuits, then compare it with sweep. Done means clearMemos returns the authenticated account identifier and the header list includes clearMemos.
Written by the indexing model from the issue text.
Assessment
- Domain
- authentication, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100