OpenZeppelin / OpenZeppelin/compact-contracts

L-06: clearMemos Does Not Return the Authenticated Identifier

Open Beginner friendly
#804 1 comment 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-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

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.