Skip to content

security(openclaw): enforce the XPR transfer cap centrally (0.8.4) - #85

Merged
paulgnz merged 1 commit into
mainfrom
security/central-transfer-cap
Sep 24, 2026
Merged

paulgnz merged 1 commit into
mainfrom
security/central-transfer-cap

Conversation

@paulgnz

@paulgnz paulgnz commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Fixes an external report: bundled skill tools could sign XPR transfers without the documented MAX_TRANSFER_AMOUNT cap.

Before: the cap was enforced only by the core plugin tools. The skill check added in #64 read an undocumented variable (MAX_TRANSFER_XPR) and only covered some handlers. defi_create_otc, loan_supply, loan_repay, xmd_mint and gov_post_proposal had no cap at all.

After: assertTransferCap runs in both signing paths:

  • createCliApi, which every skill signs through
  • createCliSession, used by the core tools

It totals every XPR transfer the agent sends in the transaction, so splitting a transfer doesn't get around it, and refuses anything above MAX_TRANSFER_AMOUNT (default 1,000 XPR).

  • A maxTransferAmount set in plugin config is passed through, and skills inherit it.
  • Existing MAX_TRANSFER_XPR settings still work.
  • The default RPC in createCliSession moves from greymass to Saltant.

Tests: 8 new, including the reporter's 9,999,999 XPR OTC case, which is now refused before it reaches the signer. openclaw passes 214. Plugin and skills build clean.

…ning layer (0.8.4)

External report (skill tools bypass MAX_TRANSFER_AMOUNT): the documented cap was only
enforced by core plugin tools. #64 added a per-skill check reading an undocumented
MAX_TRANSFER_XPR, and it covered only some handlers: defi_create_otc, loan_supply/repay,
xmd_mint and gov_post_proposal signed with no cap (repro: 9,999,999 XPR to an OTC escrow).

Every signed transaction now passes assertTransferCap in createCliApi (all skills) and
createCliSession (core tools): the total XPR the agent sends via eosio.token::transfer in
one transaction is summed and refused above MAX_TRANSFER_AMOUNT (smallest units; default
1,000 XPR). An explicit plugin-config maxTransferAmount is passed through and becomes the
process default so skills inherit it; legacy MAX_TRANSFER_XPR is still honored. Skills'
early checks now read the documented variable. createCliSession's default RPC moves from
greymass to Saltant. 8 new tests (openclaw 214).
@paulgnz
paulgnz merged commit 46b0098 into main Sep 24, 2026
7 checks passed
@paulgnz
paulgnz deleted the security/central-transfer-cap branch September 24, 2026 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant