Security[SEC-I01 H05]: whitelist code ID audit must exclude fee-on-transfer and rebase tokens [SEC-I02] #448

Closed
opened 2026-06-30 15:46:22 +00:00 by totdking · 14 comments
totdking commented 2026-06-30 15:46:22 +00:00 (Migrated from gitlab.com)

Fee-on-transfer issue of I01 H05 gap

Fee-on-transfer issue of I01 H05 gap
totdking commented 2026-06-30 15:48:17 +00:00 (Migrated from gitlab.com)

changed title from Security: whitelist code ID audit must exclude fee-on-transfer and rebase tokens [SEC-I02] to Security[SEC-I01 H05]: whitelist code ID audit must exclude fee-on-transfer and rebase tokens [SEC-I02]

<p>changed title from <code class="idiff">Security: whitelist code ID audit must exclude fee-on-transfer and rebase tokens [SEC-I02]</code> to <code class="idiff">Security<span class="idiff left right addition">[SEC-I01 H05]</span>: whitelist code ID audit must exclude fee-on-transfer and rebase tokens [SEC-I02]</code></p>
totdking commented 2026-06-30 15:48:17 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
totdking commented 2026-06-30 15:48:41 +00:00 (Migrated from gitlab.com)

Summary

The limit order escrow system records the declared amount from CW20 Send messages without verifying that the actual balance received matches the declared value. If a whitelisted CW20 token deducts a fee on transfer, the pair credits the full declared amount to PENDING_ESCROW but receives less in its real balance. Repeated place-and-cancel cycles drain the pair's token balance below the sum of all outstanding PENDING_ESCROW values.

The root cause is not in the escrow logic itself (which uses correct checked arithmetic) but in the absence of an explicit constraint requiring that whitelisted code IDs be audited to confirm they do not implement fee-on-transfer or rebase mechanics before being added via AddWhitelistedCodeId.


What Was Checked

  • smartcontracts/contracts/pair/src/limit_placement.rs lines 183-287: maker fee computed from declared amount field (plan.item.amount), not from actual balance delta received. PENDING_ESCROW incremented by declared_amount - maker_fee. Total_maker_fee queued as CW20 Transfer to treasury in the same Response.
  • Example with declared_amount=1000, cw20 fee-on-transfer=1% (10 utoken), maker_fee=5 utoken: pair receives 990 real balance, PENDING_ESCROW += 995, treasury gets 5, pair balance after = 985, shortfall per order = 10.
  • smartcontracts/contracts/factory/src/contract.rs lines 200-212: CW20 code ID whitelist check runs at pair creation only. Not rechecked on swap, provide, or limit placement.
  • docs/security-model.md: no explicit constraint on fee-on-transfer or rebase token admission via AddWhitelistedCodeId.

Expected (per checklist)

docs/security-model.md or a whitelist governance checklist explicitly states that code IDs submitted for whitelisting must be audited to confirm: no fee-on-transfer deduction, no rebase or elastic supply mechanics, no balance-manipulation on transfer. This constraint must be documented before governance adds any new code ID in production.


Actual

No such constraint exists in any documentation. The whitelist governance process is not documented with token safety requirements.


Suggested Fix

Add a section to docs/security-model.md under the CW20 whitelist policy stating:

  • Any code ID submitted for AddWhitelistedCodeId must be reviewed and confirmed to not implement fee-on-transfer, transfer tax, elastic supply, or any mechanic that causes the recipient balance to differ from the declared transfer amount.
  • Governance must attach audit evidence or source review when adding a new code ID.
  • Optionally: add a balance-delta assertion in the limit placement CW20 Receive handler that compares the declared amount against the contract's balance before and after receipt, reverting if they differ.

Verification Checklist

  • docs/security-model.md includes explicit constraint: whitelisted code IDs must be audited for fee-on-transfer and rebase mechanics
  • Whitelist governance process references this constraint when adding new code IDs
  • Optional: balance-delta assertion added to limit placement escrow funding to catch discrepancy at placement time

Cc: @PlasticDigits

### Summary The limit order escrow system records the declared amount from CW20 Send messages without verifying that the actual balance received matches the declared value. If a whitelisted CW20 token deducts a fee on transfer, the pair credits the full declared amount to PENDING_ESCROW but receives less in its real balance. Repeated place-and-cancel cycles drain the pair's token balance below the sum of all outstanding PENDING_ESCROW values. The root cause is not in the escrow logic itself (which uses correct checked arithmetic) but in the absence of an explicit constraint requiring that whitelisted code IDs be audited to confirm they do not implement fee-on-transfer or rebase mechanics before being added via AddWhitelistedCodeId. --- ### What Was Checked - `smartcontracts/contracts/pair/src/limit_placement.rs` lines 183-287: maker fee computed from declared amount field (plan.item.amount), not from actual balance delta received. PENDING_ESCROW incremented by declared_amount - maker_fee. Total_maker_fee queued as CW20 Transfer to treasury in the same Response. - Example with declared_amount=1000, cw20 fee-on-transfer=1% (10 utoken), maker_fee=5 utoken: pair receives 990 real balance, PENDING_ESCROW += 995, treasury gets 5, pair balance after = 985, shortfall per order = 10. - `smartcontracts/contracts/factory/src/contract.rs` lines 200-212: CW20 code ID whitelist check runs at pair creation only. Not rechecked on swap, provide, or limit placement. - `docs/security-model.md`: no explicit constraint on fee-on-transfer or rebase token admission via AddWhitelistedCodeId. --- ### Expected (per checklist) `docs/security-model.md` or a whitelist governance checklist explicitly states that code IDs submitted for whitelisting must be audited to confirm: no fee-on-transfer deduction, no rebase or elastic supply mechanics, no balance-manipulation on transfer. This constraint must be documented before governance adds any new code ID in production. --- ### Actual No such constraint exists in any documentation. The whitelist governance process is not documented with token safety requirements. --- ### Suggested Fix Add a section to `docs/security-model.md` under the CW20 whitelist policy stating: - Any code ID submitted for AddWhitelistedCodeId must be reviewed and confirmed to not implement fee-on-transfer, transfer tax, elastic supply, or any mechanic that causes the recipient balance to differ from the declared transfer amount. - Governance must attach audit evidence or source review when adding a new code ID. - Optionally: add a balance-delta assertion in the limit placement CW20 Receive handler that compares the declared amount against the contract's balance before and after receipt, reverting if they differ. --- ### Verification Checklist - [ ] `docs/security-model.md` includes explicit constraint: whitelisted code IDs must be audited for fee-on-transfer and rebase mechanics - [ ] Whitelist governance process references this constraint when adding new code IDs - [ ] Optional: balance-delta assertion added to limit placement escrow funding to catch discrepancy at placement time Cc: @PlasticDigits
totdking commented 2026-06-30 18:37:55 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
Brouie commented 2026-06-30 19:06:57 +00:00 (Migrated from gitlab.com)

mentioned in merge request !985

mentioned in merge request !985
Brouie commented 2026-06-30 19:08:57 +00:00 (Migrated from gitlab.com)

Handled the docs side of this. The fee-on-transfer prohibition was already in (#377), but rebase / elastic-supply / reflection tokens weren't named, and there was no explicit audit-evidence requirement — which is the actual H05 gap.

  • security-model.md § Code ID Whitelist: reframed the constraint as a balance-stability requirement covering BOTH fee-on-transfer and rebase/elastic-supply (balance changes after receipt with no transfer), and now requires source review + recorded audit evidence before AddWhitelistedCodeId, not checksum match alone.
  • cw20-whitelist-policy.md: added rebase/elastic-supply to the prohibited list and the table, plus a source-review step (no balance mutation outside an explicit transfer) and an attach-audit-evidence step in pre-whitelist verification.

Both balance-stability docs-check scripts still pass.

That covers checklist items 1 and 2. The optional item 3 (runtime balance-delta assertion in the limit-placement escrow funding) is a contract change, not docs — I left it tracked here as a separate follow-up rather than folding it in.

MR !985, branch qa/448-token-whitelist-rebase-docs, commit 1a8ab017. Needs review/merge @PlasticDigits — leaving open for verification.

Handled the docs side of this. The fee-on-transfer prohibition was already in (#377), but rebase / elastic-supply / reflection tokens weren't named, and there was no explicit audit-evidence requirement — which is the actual H05 gap. - `security-model.md` § Code ID Whitelist: reframed the constraint as a balance-stability requirement covering BOTH fee-on-transfer and rebase/elastic-supply (balance changes after receipt with no transfer), and now requires source review + recorded audit evidence before `AddWhitelistedCodeId`, not checksum match alone. - `cw20-whitelist-policy.md`: added rebase/elastic-supply to the prohibited list and the table, plus a source-review step (no balance mutation outside an explicit transfer) and an attach-audit-evidence step in pre-whitelist verification. Both balance-stability docs-check scripts still pass. That covers checklist items 1 and 2. The optional item 3 (runtime balance-delta assertion in the limit-placement escrow funding) is a contract change, not docs — I left it tracked here as a separate follow-up rather than folding it in. MR !985, branch `qa/448-token-whitelist-rebase-docs`, commit `1a8ab017`. Needs review/merge @PlasticDigits — leaving open for verification.
PlasticDigits commented 2026-06-30 22:00:39 +00:00 (Migrated from gitlab.com)

mentioned in commit 658aeae727

mentioned in commit 658aeae72700d86a0dda74f1e32e53f87acf9ae0
PlasticDigits commented 2026-06-30 22:13:43 +00:00 (Migrated from gitlab.com)

Verification — #448 (SEC-I01 H05 / SEC-I02)

Verified on main at merge commit 658aeae7 (MR !985, 1a8ab017).

Checklist

Item Result How verified
docs/security-model.md states whitelisted code IDs must be audited for fee-on-transfer and rebase/elastic-supply mechanics, with source review + recorded audit evidence before AddWhitelistedCodeId PASS grep on docs/security-model.md — Balance-stability requirement paragraph cites #377/#448, names fee-on-transfer/transfer-tax and rebase/elastic-supply/reflection, requires source review and audit evidence (not checksum match alone), links cw20-whitelist-policy.md.
Whitelist governance process references this constraint when adding new code IDs PASS docs/runbooks/cw20-whitelist-policy.md — prohibited templates table includes rebase/elastic-supply; pre-whitelist steps 4 (source review) and 5 (attach audit evidence). Cross-linked from security-model.md and launch checklist Phase 0 (cw20-whitelist-policy.md).
Optional: balance-delta assertion in limit-placement escrow funding SKIP Intentionally deferred (contract change). limit_placement.rs has no balance-delta check; issue comment and MR !985 note this as a separate follow-up.

Additional checks

Check Result How verified
Adversarial regression documents fee-on-transfer reserve desync PASS cd smartcontracts && cargo test fee_on_transfer -- --nocapture → fee_on_transfer_creates_reserve_imbalance ok
No unintended contract changes in #448 scope PASS MR !985 is docs-only (security-model.md, cw20-whitelist-policy.md); working tree clean on main.

Follow-ups (non-blocking)

  • Runtime balance-delta assertion in pair limit-placement CW20 Receive (optional item 3) — track as a separate contract issue if desired.
  • Cross-doc alignment: docs/runbooks/launch-checklist.md Phase 0 still says "No fee-on-transfer templates" in the bullet text (links to the full policy); docs/security-posture.md and docs/runbooks/cw20-code-id-ops.md mention fee-on-transfer only. Consider naming rebase/elastic-supply in those summaries for operator skim-reads.
  • Regression target: add make verify-issue-448 (doc invariant script + fee_on_transfer test) mirroring other SEC doc gates.

Closing — docs acceptance criteria satisfied on main.

## Verification — #448 (SEC-I01 H05 / SEC-I02) Verified on `main` at merge commit `658aeae7` (MR !985, `1a8ab017`). ### Checklist | Item | Result | How verified | |------|--------|--------------| | `docs/security-model.md` states whitelisted code IDs must be audited for fee-on-transfer **and** rebase/elastic-supply mechanics, with source review + recorded audit evidence before `AddWhitelistedCodeId` | **PASS** | `grep` on `docs/security-model.md` — **Balance-stability requirement** paragraph cites #377/#448, names fee-on-transfer/transfer-tax and rebase/elastic-supply/reflection, requires source review and audit evidence (not checksum match alone), links `cw20-whitelist-policy.md`. | | Whitelist governance process references this constraint when adding new code IDs | **PASS** | `docs/runbooks/cw20-whitelist-policy.md` — prohibited templates table includes rebase/elastic-supply; pre-whitelist steps 4 (source review) and 5 (attach audit evidence). Cross-linked from `security-model.md` and launch checklist Phase 0 (`cw20-whitelist-policy.md`). | | Optional: balance-delta assertion in limit-placement escrow funding | **SKIP** | Intentionally deferred (contract change). `limit_placement.rs` has no balance-delta check; issue comment and MR !985 note this as a separate follow-up. | ### Additional checks | Check | Result | How verified | |-------|--------|--------------| | Adversarial regression documents fee-on-transfer reserve desync | **PASS** | `cd smartcontracts && cargo test fee_on_transfer -- --nocapture` → `fee_on_transfer_creates_reserve_imbalance` **ok** | | No unintended contract changes in #448 scope | **PASS** | MR !985 is docs-only (`security-model.md`, `cw20-whitelist-policy.md`); working tree clean on `main`. | ### Follow-ups (non-blocking) - **Runtime balance-delta assertion** in pair limit-placement CW20 `Receive` (optional item 3) — track as a separate contract issue if desired. - **Cross-doc alignment:** `docs/runbooks/launch-checklist.md` Phase 0 still says "No fee-on-transfer templates" in the bullet text (links to the full policy); `docs/security-posture.md` and `docs/runbooks/cw20-code-id-ops.md` mention fee-on-transfer only. Consider naming rebase/elastic-supply in those summaries for operator skim-reads. - **Regression target:** add `make verify-issue-448` (doc invariant script + `fee_on_transfer` test) mirroring other SEC doc gates. Closing — docs acceptance criteria satisfied on `main`.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-30 22:13:44 +00:00
Brouie commented 2026-07-01 11:19:30 +00:00 (Migrated from gitlab.com)

mentioned in issue #447

mentioned in issue #447
totdking commented 2026-07-02 16:13:11 +00:00 (Migrated from gitlab.com)

mentioned in commit 9ff4ea7b60

mentioned in commit 9ff4ea7b6091af242260e3566c86b126f590411c
totdking commented 2026-07-02 16:14:07 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1007

mentioned in merge request !1007
PlasticDigits commented 2026-08-20 03:28:03 +00:00 (Migrated from gitlab.com)

mentioned in issue #581

mentioned in issue #581
PlasticDigits commented 2026-08-20 03:37:29 +00:00 (Migrated from gitlab.com)

mentioned in issue #582

mentioned in issue #582
PlasticDigits commented 2026-08-20 03:37:48 +00:00 (Migrated from gitlab.com)

marked as related to #582

marked as related to #582
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#448
No description provided.