Garden Protocol Security Assessment: Trail of Bits

Garden Protocol Security Assessment: Trail of Bits

Technical

// Technical
TL;DR, Trail of Bits audited Garden's GardenStaker, HTLC, and FEEAccount contracts across a two week engagement. Nine findings were identified across High, Medium, Low, and Informational severity; no Critical issues. Six were resolved directly in code; three were addressed through protocol level operational changes.

Garden engaged Trail of Bits to conduct a security assessment of the protocol's onchain contracts implementing cross chain BTC swaps via HTLCs, fee distribution to fillers, and the staking and delegation mechanics that underpin solver participation. The review was conducted by Richie Humphrey and Vara Prasad Bandaru, with Josselin Feist as engineering director, over two engineer weeks. A fix review was subsequently conducted with the summary report delivered in April 2024.

Trail of Bits noted that the code itself was high quality with clear security attention in its design. The primary challenge of the review was not understanding the contracts individually but understanding how they interacted with the larger system, particularly the coordination logic between the orderbook, fee signing, and filler selection that shapes how the onchain contracts are actually used.

Scope

Three onchain contracts were in scope:

  • GardenStaker: manages filler registration, delegator staking, voting power, and stake lifecycle
  • GardenHTLC: implements the HTLC mechanism for swap initiation, redemption, and refund
  • FEEAccount: handles fee payment channels between the fee manager, fillers, and delegators (previously called GardenFEEAccount) 

Trail of Bits used Slither for static analysis and Echidna for stateful invariant fuzzing on GardenStaker. Two properties were tested and both passed: that the SEED token balance of the staker contract equals the net sum of all stakes, and that all fillers hold the filler role exclusively.

Findings

Trail of Bits identified nine findings. The severity breakdown: three High, three Medium, two Low, one Informational. No Critical severity issues were identified.

TOB-CATALOG-1; Filler liquidity vulnerable to a DoS attack | High

Because there is no penalty for refunding orders, an attacker can initiate swap orders with no intention of completing them, locking up filler liquidity for the duration of the HTLC timelock and then calling refund after expiry. Repeated at scale, this would exhaust available filler capacity and effectively disable the swap system. 

Exploitation difficulty is rated High as the attacker must lock their own funds for twice the filler's timelock duration, making the attack capital intensive. Trail of Bits proposed several mitigation directions: requiring initiator deposits returned on successful redemption, charging initiation fees, or requiring SEED stakes from initiators.

TOB-CATALOG-2; Anyone can cause the FeeAccount template to self-destruct | High

The GardenFEEAccountFactory constructor deploys a GardenFEEAccount (now called FEEAccount) template contract without initializing it or disabling its initializers. Because FEEAccount.close and .settle both call closeChannel, which triggers selfdestruct, an attacker could initialize the template with their own addresses and call close on it, destroying the template. Since clones delegate-call to the template, all subsequent calls to active fee channels would become no-operations and deposited tokens would be permanently lost. 

TOB-CATALOG-3; Fees may be withdrawn prior to initiating an order | Medium

The fee manager pre-signs claim messages for delegators before a swap order is initiated onchain, using the secretHash provided by the creator. A malicious delegator who has access to this pre-signed message and knows the secret can claim fees without the corresponding swap ever being initiated. This is a protocol flow ordering issue, the vulnerability exists in how the system sequences its signing operations relative to onchain initiation.

TOB-CATALOG-4; A creator can claim fees without redeeming the order | Medium

The fee payment HTLCs and the swap HTLCs share the same timelock duration (48 hours) and the same secret. Since the secret is known only to the creator, they can wait until the swap HTLC expires, call refund to recover their locked tokens, and then use the secret to claim delegator fees for an order they never completed. Garden identified this issue independently during the review.

TOB-CATALOG-5; Delegators can extend their stake at a higher voting multiple | Low

The extend function in DelegateManager correctly upgrades a delegator's voting multiplier when extending for a longer period, but does not downgrade it when extending for a shorter period. A delegator who originally staked for four years could extend for six months near the end of their lock period and retain the four-year multiplier indefinitely.

Garden acknowledged this as intentional: the protocol is designed to reward long-duration stakers, and retaining the multiplier for completed lock periods aligns with that goal. Garden added documentation to clarify the intended behaviour.

TOB-CATALOG-6; Inconsistent use of the term "expiry" | Informational

The term expiry was used to mean an absolute block number in GardenStaker but a relative duration (number of blocks) in GardenHTLC. NatSpec comments and the README compounded the confusion by incorrectly describing expiry as a block number across the codebase. This semantic inconsistency creates a maintainability risk, a developer reasoning about expiry across both contracts could introduce incorrect behaviour.

TOB-CATALOG-7; Improper handling of delegateStakeIDs disables critical functionality | High

When a filler deregisters and calls refund, the Filler struct is deleted from the fillers mapping using Solidity's delete. However, the delegateStakeIDs field is an OpenZeppelin EnumerableSet, which internally uses both an array and a mapping. Solidity's delete zeroes the array length but does not clear the mapping's index entries. When subsequent calls attempt to remove entries from the set, they read a nonzero valueIndex from the stale mapping but encounter a zero-length array, causing a panic revert.

The practical consequence: any delegator whose filler deregisters and calls refund permanently loses the ability to call changeVote or refund on their own stake. Even if the filler re-registers, existing stake associations are not restored, the stakes become permanently locked. This issue was identified via Slither.

TOB-CATALOG-8; A user cannot renew their stake for the maximum duration | Low

The renew function computes the new expiry as block.number + newLockBlocks. When a user passes the maximum uint256 value to represent indefinite staking, this addition overflows and causes the transaction to revert. A user whose stake expires cannot renew it for the maximum duration.

TOB-CATALOG-9; Delegators lose rewards when HTLCs expire before others in a channel | Medium

The claim function in GardenFEEAccount iterates through an array of HTLCs and silently excludes any that have expired, without reverting or tracking the shortfall. In a payment channel with multiple active HTLCs, if one expires before the delegator claims due to delays in swap completion, the associated rewards are irrecoverably lost. Exploitation difficulty is rated High because triggering the condition requires a specific sequence of timing events across multiple swaps.

Action

Six of the nine findings were resolved in code. Three were addressed through protocol-level operational changes.

Resolved in code:

  • TOB-CATALOG-2 was fixed by adding an initialize function to the GardenFEEAccount implementation that calls _disableInitializers, preventing any future initialization of the template contract.
  • TOB-CATALOG-5 was acknowledged as an intentional design decision and resolved by adding documentation clarifying the intended multiplier retention behaviour.
  • TOB-CATALOG-6 was resolved by renaming the variable; expiry now consistently refers to an absolute block number, and timelock refers to a relative duration across both contracts.
  • TOB-CATALOG-7 was resolved by changing the filler deregistration logic to reset individual data members rather than deleting the entire struct, leaving delegateStakeIDs intact. This allows existing delegators to continue calling changeVote and refund, and ensures re-registration automatically reactivates their stake associations. A _checkRole check was also added to getVotes to exclude deregistered fillers from vote calculations.
  • TOB-CATALOG-8 was resolved by adding a check for the maximum duration condition in the renew function, setting stake.expiry to type(uint).max directly when the maximum lock period is selected.
  • TOB-CATALOG-9 was resolved by updating the claim function to store both claimed and submitted secrets in mappings, allowing partial claims to succeed without forfeiting rewards for other HTLCs in the same channel.

TOB-CATALOG-1, TOB-CATALOG-3, and TOB-CATALOG-4 were addressed through protocol-level operational changes. For TOB-CATALOG-1, Garden implemented a rate limit of 1.5 BTC/WBTC per address per 24 hours during the beta period, with a planned nonrefundable platform fee at public launch (live currently). For TOB-CATALOG-3, Garden reordered the fee signing flow so fillers provide their signature to FeeHub only after the user initiates on the origin chain. For TOB-CATALOG-4, Garden tightened the timing constraints between swap initiation and fee HTLC signing. Trail of Bits confirmed these mitigations were described and plausible.

Summary

Nine findings across three High, three Medium, two Low, and one Informational severity. No Critical issues. All the issues were resolved. 

Since this assessment, Garden has completed a Move application security assessment with Zellic (June 2025) and ran a competitive bug bounty through Code4rena with $37,500 in rewards across 813 submissions, targeting the HTLC architecture across Bitcoin, EVM, Solana, Sui, and Starknet.

View the full Trail of Bits report on GitHub →

Last updated

Related Blogs