Pre-auditThree days of senior audit time for $1,500, credited in full toward your Zealynx audit.3 audit days, credited toward your auditSee how →
M-12·audit-finding

A holder has no on-chain way to refuse an operator for their Special badges, and the delay that replaces it is floored at 60 seconds

Partly addressednfterc-1155marketplace
TL;DR

A holder has no on-chain way to refuse an operator for their Special badges, and the delay that replaces it is floored at 60 seconds. Final disposition: Partly addressed.

Severity
MEDIUM
Method
MManual review
CAT.

Tracker: issue #37 · Re-review ID: RR-02 · Status: Partly addressed · Verified at: generation-d

Severity: Medium Location: src/PlakxioBadge.sol:1063-1066 — _checkHolderPermits Introduced by: the M-01 fix (#17), verified at audit-v3-rereview-handoff You disclosed this yourself in re-review handoff §10(j). Filing it so it has a tracked home rather than living only in correspondence.

02Section · What's wrong

What's wrong

The M-01 fix makes the holder's refusal class-aware at the move, which is correct. The way it does that is to exempt Special entirely:

solidity
function _checkHolderPermits(address holder, address operator, uint256 id) internal view {
if (tokenClass(id) == TokenClass.Special) return;
if (settlementOptOut[holder][operator]) revert HolderOptedOut(holder, operator);
}

A holder therefore has no on-chain way to refuse an operator for their Special badges, whatever the operator's mask.

03Section · Why it matters

Why it matters

This closes M-01 and we are not asking you to reopen it — a Special is a forced-sale instrument and a holder who could refuse the market would defeat the mechanic. The problem is what is left in its place.

The holder's refusal was the one control the trust model gives a holder against a wrong or compromised operator grant. It is now absent on the highest-value class. Your stated compensating controls are the activation delay, the alerts and the Safe's hardware keys — and the activation delay's floor is still the 60-second interim placeholder (MIN_SETTLEMENT_ACTIVATION_DELAY = 60 seconds; see our comment on #3). So the compensating control for the class with no holder-side defence is itself a one-minute minimum.

Answering §10(j) directly: the residual is acceptable only once the delay floor is a real number. Fix the floor and this becomes a reasonable design trade. Leave the floor at 60 seconds and a compromised admin can whitelist a hostile Special-class operator and move every Special a minute later, with nothing a holder can sign.

04Section · Recommendation

Recommendation

  1. Merge the 1-hour floor you already wrote (see #3). That is the load-bearing part.
  2. If you want a holder-side defence for Specials specifically, the shape we would suggest is not a refusal — it is a holder-signed acknowledgement window: a Special-class operator newly whitelisted cannot move badge id until settlementActiveFrom and some longer per-class delay has passed, so the holder's protection is time rather than veto. That keeps the forced sale intact and gives the holder the thing a refusal was giving them: notice.

Related: the refusal also reports success it does not deliver — filed separately.

05Section · Remediation

Remediation

Partly addressed. The delay condition is implemented and verified; the Special-holder exemption is retained by design and has not been eliminated.

The condition we attached to this finding is met. The badge enforces a six-hour minimum activation delay at construction, and production deployment of 72 hours is enforced separately (see L-11). That implementation is verified in the reviewed code and on the deployed testnet instance.

The second recommendation — a longer, Special-only acknowledgement window — was not built. We consider the stated rationale supportable: a delay protects only a party who can act inside it, and a Special holder has no action available, because there is no refusal by design, no wallet-to-wallet move inside the walled garden, and no burn. The only party who can act on a wrong or hostile Special-class grant is the administrator, by revoking, and revocation is never delayed. A longer timer would give the administrator more time to do what the first delay already times, and give the holder notice of something they cannot change. What replaces it is legibility rather than veto: the per-badge authority view described under L-09.

The exposure is retained, not removed. Under the documented compromised-Safe assumption a hostile Special-class operator can be whitelisted and, after the delay, move every Special, with nothing a holder can sign. The compensating controls are the delay, the two-step delayed administrator transfer, off-chain alerting and incident procedure. On the alerting: a claimed external-monitor worst-case gap of three to six hours reaches the six-hour testnet floor's boundary rather than establishing a margin inside it, and we state that as the client did rather than claiming more. Off-chain monitoring and key custody were not independently verified by this review.

06Section · Verification provenance

Verification provenance

Final disposition: Partly addressed. Verified at generation-d, commit bcf18bb2926589bb8538fa8c322eabc871ff2801. This finding was assessed in the generation-d mitigation review. The report-wide scope and evidence limitations remain applicable; see the final report overview.

Status
Partly addressed
M-12