Skip to content

fix(hk-sbtc-real-receiver-v2): require the owner's own flash-loan in the callback (C7 front-run, ajv.4.11) - #140

Merged
mattglory merged 1 commit into
mattglory:mainfrom
unixwhisperer:security-lead/ajv-4-11-receiver-v2-owner-callback
Oct 27, 2026
Merged

mattglory merged 1 commit into
mattglory:mainfrom
unixwhisperer:security-lead/ajv-4-11-receiver-v2-owner-callback

Conversation

@unixwhisperer

Copy link
Copy Markdown
Collaborator

What

hk-sbtc-real-receiver-v2 (#115, not deployed) relied on the owner's arm alone for C7. flashstack-sbtc-core calls the receiver without as-contract (flashstack-sbtc-core.clar:77), so tx-sender in execute-sbtc-flash is the flash-loan caller. arm-loan and flash-loan are separate transactions, so a stranger could front-run the armed amount: the swap legs would run on the owner's settings and spend the owner's pre-funded shortfall. This was raised in the #136 review.

Change

  • The callback asserts tx-sender == contract-owner right after the B4/B5 caller gate, with a new error u612 (ERR-NOT-LOAN-OWNER). A stranger's loan now reverts before the arm is read, so the arm survives for the owner.
  • The C7 header comment is updated, and so are the line references in THREAT_MODEL.
  • RECEIVER_VETTING C7 gains a short note: with lenders that call without as-contract (both live cores and the v3 pools), an arm alone leaves a front-run window, and a tx-sender check closes it.

Tests

  • New test: with a loan armed, two strangers each get u612, the arm is unchanged, and the owner's loan still reaches Bitflow leg 1 (u605, the simnet limit described in the file header).
  • The ownership test also checks that the old owner is refused (u612).
  • Mutation-checked: removing the line turns 2 tests red.
  • Full suite: 358 passed, 3 skipped.

Deployment status

Not deployed: Hiro returns 404 for hk-sbtc-real-receiver-v2 at SP3NZYZA…, SP20XD46… and SPR9PQAN… (v1 at SP3NZYZA… returns 200). Nothing deployed changes.

Follows up Flashstack-ajv.4.11.

🤖 Generated with Claude Code

… in the callback (ajv.4.11)

flashstack-sbtc-core calls the receiver without as-contract, so tx-sender
in execute-sbtc-flash is whoever called flash-loan. arm-loan and flash-loan
are separate transactions, so an arm alone let a stranger front-run the
armed amount and run the swap legs on the owner's settings. The callback
now asserts tx-sender is the owner right after the B4 gate (ERR u612).

Receiver is not deployed (404 at SP3NZYZA..., SP20XD46..., SPR9PQAN...).
@vercel

vercel Bot commented Oct 22, 2026

Copy link
Copy Markdown

@unixwhisperer is attempting to deploy a commit to the matt glory's projects Team on Vercel.

A member of the Team first needs to authorize it.

@mattglory mattglory left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: adds the tx-sender==owner check right after the B4 caller gate, closing the arm front-run. Tests confirm the arm survives a stranger's rejected attempt and the owner's own loan still reaches leg 1, plus the post-ownership-transfer case (old owner locked out, new owner can arm). Approving.

@mattglory
mattglory merged commit 13fe570 into mattglory:main Oct 27, 2026
4 of 6 checks passed
mattglory pushed a commit that referenced this pull request Oct 27, 2026
… callback

Follow-up to #136, per Matt's review. The core calls execute-stx-flash
without as-contract, so tx-sender is whoever called flash-loan. With only
the arm check, a stranger could call flash-loan with the exact armed
amount before the owner's own transaction landed. The callback now also
asserts tx-sender == owner (err u403), the same check #140 added to
hk-sbtc-real-receiver-v2.

Checked in simnet, with the snippet extracted from both pages and pointed
at the local core: before this change the stranger's front-run returned
(ok true); after it, it returns (err u403). The owner's own loan still
succeeds, and the arm stays single-use (err u402).
mattglory pushed a commit that referenced this pull request Oct 27, 2026
Re-checked on main @ ba04efd (2026-10-27):
- sbtc-pool-v3 368 -> 376 lines (F-11 share-price rescale, #138); pools
  705 -> 713; Tier 2 1,159 -> 1,167. Tier 1 unchanged at 508.
- Tests 357 -> 379 passing (3 skipped), 40 -> 41 files.
- The v2/v3 pool pairs no longer differ only in admin code: they also
  carry the F-8 pause gate, the F-9 reentrancy lock and (sbtc only) the
  F-11 price scale. Replaces the stale '14 lines, all admin-related'.
- Lists the reentrancy-lock and share-price suites as direct v3 tests,
  notes F-11 fixed in sbtc-pool-v3, and §6e as written (#139), not run.
mattglory added a commit that referenced this pull request Oct 27, 2026
…026-10-27

docs(security): refresh AUDIT_SCOPE after #138-#140
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.

2 participants