Prepared by:
HALBORN
Last Updated 04/28/2026
Date of Engagement: March 9th, 2026 - April 9th, 2026
100% of all REPORTED Findings have been addressed
All findings
67
Critical
3
High
5
Medium
17
Low
33
Informational
9
This security assessment was commissioned by Peridot Protocol, a DeFi lending, borrowing, and margin trading platform built on the Stellar/Soroban blockchain. The review was conducted by Halborn's experienced security team, focusing on the on-chain components of the Peridot smart contract suite. The assessment covered all functionalities within the ReceiptVault, MarginController, SimplePeridottroller, SwapAdapter, JumpRateModel, and SmartAccount contracts from March 9th, 2026, to April 9th, 2026. The primary objective of this engagement was to identify potential vulnerabilities, verify module reliability, and enhance the overall security posture of the protocol.
The team at Halborn assigned a full-time security engineer to verify the security of the smart contracts. The security engineer is a blockchain and smart-contract security expert with advanced penetration testing, smart-contract hacking, and deep knowledge of multiple blockchain protocols.
The purpose of this assessment is to:
Ensure that smart contract functions operate as intended
Identify potential security issues with the smart contract
In summary, Halborn identified some improvements to reduce the likelihood and impact of risks, which were addressed by the Peridot team. The main recommendations were the following:
Fix the core interest and exchange-rate accounting — A double-counting bug inflates borrow interest and distorts the exchange rate across all markets; the vault exchange rate is also vulnerable to inflation via direct token donations. These accounting errors undermine the solvency of the entire protocol.
Protect collateral across the full margin position lifecycle — Collateral backing open margin positions must be held in custody by the protocol contract rather than the user's wallet, and health checks must correctly apply the collateral factor when evaluating position safety. Without these fixes, positions can be opened or held while effectively uncollateralized.
Repair the liquidation mechanism — Several bugs prevent liquidators from successfully closing underwater positions: repayment occurs before collateral availability is confirmed, account-level checks incorrectly block position-level liquidations, and valid liquidations can be aborted mid-execution. These must be resolved for the protocol to enforce solvency and recover bad debt.
Enforce fresh oracle prices at every critical decision point — Prices are not refreshed when borrowing, liquidating, or managing positions, and fallback prices carry no timestamp. Stale prices can be exploited to borrow against overvalued collateral or avoid liquidation; all entry points must require a live price update before proceeding.
Prevent on-chain configuration from silently expiring — Critical parameters such as collateral factors, interest models, and supply caps are stored in time-limited ledger entries that are not properly renewed. When these expire, the protocol operates with unsafe defaults or stops functioning entirely.
An unwaveringly thorough multi-phase strategy was employed for this assessment. The process comprised the following major phases:
Research & code mapping: identification of critical modules (ReceiptVault, MarginController, SimplePeridottroller, SwapAdapter, JumpRateModel, SmartAccount, storage layers, interest rate models, and oracle integrations).
Manual review of lending and borrowing mechanics, exchange rate calculations, margin position lifecycle, liquidation flows, reward accounting, and access control integrations.
Automated static scans and linter passes to collect candidate defects.
On-chain unit and integration tests executed in the Soroban test environment, including PoCs that reproduce accounting errors, liquidation breakage, and price manipulation edge cases.
Confidence in coverage was achieved by cross-validating manual findings with on-chain test replays and PoCs. Priority was given to issues that could lead to fund loss, permanent state corruption, bad debt accumulation, or irreversible operational locking.
| EXPLOITABILITY METRIC () | METRIC VALUE | NUMERICAL VALUE |
|---|---|---|
| Attack Origin (AO) | Arbitrary (AO:A) Specific (AO:S) | 1 0.2 |
| Attack Cost (AC) | Low (AC:L) Medium (AC:M) High (AC:H) | 1 0.67 0.33 |
| Attack Complexity (AX) | Low (AX:L) Medium (AX:M) High (AX:H) | 1 0.67 0.33 |
| IMPACT METRIC () | METRIC VALUE | NUMERICAL VALUE |
|---|---|---|
| Confidentiality (C) | None (C:N) Low (C:L) Medium (C:M) High (C:H) Critical (C:C) | 0 0.25 0.5 0.75 1 |
| Integrity (I) | None (I:N) Low (I:L) Medium (I:M) High (I:H) Critical (I:C) | 0 0.25 0.5 0.75 1 |
| Availability (A) | None (A:N) Low (A:L) Medium (A:M) High (A:H) Critical (A:C) | 0 0.25 0.5 0.75 1 |
| Deposit (D) | None (D:N) Low (D:L) Medium (D:M) High (D:H) Critical (D:C) | 0 0.25 0.5 0.75 1 |
| Yield (Y) | None (Y:N) Low (Y:L) Medium (Y:M) High (Y:H) Critical (Y:C) | 0 0.25 0.5 0.75 1 |
| SEVERITY COEFFICIENT () | COEFFICIENT VALUE | NUMERICAL VALUE |
|---|---|---|
| Reversibility () | None (R:N) Partial (R:P) Full (R:F) | 1 0.5 0.25 |
| Scope () | Changed (S:C) Unchanged (S:U) | 1.25 1 |
| Severity | Score Value Range |
|---|---|
| Critical | 9 - 10 |
| High | 7 - 8.9 |
| Medium | 4.5 - 6.9 |
| Low | 2 - 4.4 |
| Informational | 0 - 1.9 |
Critical
3
High
5
Medium
17
Low
33
Informational
9
| Security analysis | Risk level | Remediation Date |
|---|---|---|
| Missing TTL Bumps for Configuration Keys Bypasses Risk Checks and Bricks Liquidation | Critical | Solved - 03/16/2026 |
| Accrual Logic Flaw Leading to Double-Counted Interest and Inflated Cash | Critical | Solved - 03/28/2026 |
| withdraw_collateral Ignores Open Position Locks, Enabling Uncollateralized Debt | Critical | Solved - 04/14/2026 |
| Wrong Index Baseline Enables Retroactive Reward Claims by New Depositors | High | Solved - 04/10/2026 |
| Unhandled Cross-Contract Panics in sum_positions_usd Permanently Lock Accounts | High | Solved - 04/10/2026 |
| Margin Position Lifecycle Bugs Enable Stuck Positions and Bad Debt | High | Solved - 04/15/2026 |
| Repayment Before Seize Validation Causes Liquidator Loss and Protocol Bad Debt | High | Solved - 04/10/2026 |
| Stale Oracle Cache Enables Protocol-Wide Price Exploitation | High | Solved - 04/13/2026 |
| Post-Repay max_redeem_ptokens in SeizeContext Aborts Valid Liquidations | Medium | Solved - 04/07/2026 |
| Stale Cross-Market Borrow Balance Enables Undercollateralized Borrowing | Medium | Solved - 04/10/2026 |
| Removed Markets Retain Phantom Collateral; 50% CF Default Enables Overborrowing | Medium | Solved - 04/08/2026 |
| Unbounded Entered Markets Enable Compute-Budget DoS on Liquidations | Medium | Solved - 04/10/2026 |
| Hardcoded u32::MAX Allowance Expiration Causes approve() to Trap | Medium | Solved - 03/16/2026 |
| LiquidationBonus Stored but Never Applied in Margin Liquidation | Medium | Solved - 04/15/2026 |
| ABI Mismatch Permanently Breaks All Margin Position Liquidations | Medium | Solved - 04/13/2026 |
| Stale Sub-Invocation Auth Entries Break Liquidations And Repayments | Medium | Solved - 04/17/2026 |
| Insufficient Slippage and Deadline Controls Enable MEV Sandwich Attacks | Medium | Solved - 04/16/2026 |
| TTL Expiry and Panicking External Calls Can Permanently Brick Users and the Vault | Medium | Solved - 03/28/2026 |
| Exchange Rate Inflation Via Direct Token Donation Dilutes Subsequent Deposits | Medium | Solved - 03/26/2026 |
| Borrow Cap Uses Interest-Inflated TotalBorrowed, Eventually Disabling Borrowing | Medium | Solved - 03/28/2026 |
| Timeless Fallback Price and Stale Cache Corrupt All Health Checks | Medium | Solved - 04/10/2026 |
| get_health_factor Omits Collateral Factor, Overstating Position Safety | Medium | Solved - 04/16/2026 |
| Account-Level Liquidity Gate Permanently Blocks Margin Position Liquidation | Medium | Solved - 04/16/2026 |
| pToken Is Not SEP-41 Compliant, Breaking Integrations | Medium | Solved - 04/01/2026 |
| close_position Does Not Return Initial Collateral, Permanently Locking User Funds | Medium | Solved - 04/15/2026 |
| Boosted Vault Withdraw Assumes Full Amount Returned, Causing Withdrawal Reverts | Low | Solved - 03/30/2026 |
| Reward Accrual Failures Are Swallowed, Causing Silent State Drift | Low | Solved - 03/30/2026 |
| Unbounded Signer Entries In Instance Storage Can Exceed Ledger Limits And Brick Accounts | Low | Solved - 03/16/2026 |
| Missing On-Demand DeFindex Liquidity Redemption in borrow() and flash_loan() DoSes Boosted Markets | Low | Solved - 04/07/2026 |
| Unguarded repay_on_behalf_for_liquidator Enables Griefing Liquidations | Low | Solved - 04/10/2026 |
| Interest Model Initialization Gap And Unvalidated Rate Relationships Enable Mispricing | Low | Solved - 03/30/2026 |
| Admin Key Centralization: Unconstrained Control Over Oracle, Risk Parameters, and Reward Configuration | Low | Solved - 04/16/2026 |
| Unvalidated Pool Address in swap_pool Allows Routing Through Arbitrary Contracts | Low | Solved - 04/13/2026 |
| Borrow-Only Auth Policy Allows Collateral-Reducing Operations Without Health Checks | Low | Solved - 03/16/2026 |
| Low TTL Constants Across Protocol Contracts Allow Critical State Archival Under Normal Inactivity | Low | Solved - 04/15/2026 |
| Flash Loan Missing Receiver Authorization Enables Forced Callbacks On Third-Party Contracts | Low | Solved - 03/28/2026 |
| Exchange Rate Uses Initial Rate When pToken Supply Is Zero | Low | Solved - 03/30/2026 |
| Double Reserve Subtraction Distorts Jump Rate Utilization | Low | Solved - 04/07/2026 |
| Failing Market Contract in claim() Blocks All Reward Claims | Low | Solved - 04/07/2026 |
| Missing Market Validation in accrue_user_market Allows Arbitrary Contract Calls | Low | Solved - 04/07/2026 |
| Unbounded Liquidation Bonus and Unvalidated Swap Adapter Enable Admin Fund Theft | Low | Solved - 04/15/2026 |
| Debt Share Floor Division Accumulates Systematic Under-Repayment Across Positions | Low | Solved - 04/15/2026 |
| Redundant Authorization Check Blocks Smart Account Creation | Low | Solved - 03/16/2026 |
| Admin Pause Controls Have No Duration Limit or Expiry | Low | Solved - 04/10/2026 |
| Stale Exchange Rate Snapshot in close_position Miscomputes Swap Amount | Low | Solved - 04/15/2026 |
| Market Remapping Misdirects Close And Liquidation For Open Positions | Low | Solved - 04/15/2026 |
| Unvalidated Swap Path Endpoints Enable Arbitrary Token Routing | Low | Solved - 04/16/2026 |
| Single-Step Admin Transfer Without Acceptance Can Permanently Lock Administrative Control | Low | Solved - 03/16/2026 |
| Untimelocked Child WASM Hash Update in SmartAccountFactory Enables Backdoored Account Deployments | Low | Solved - 03/16/2026 |
| Reward Accounting and PauseGuardian Entries Never Receive TTL Bumps | Low | Solved - 04/10/2026 |
| AMM Price Manipulation Enables Undercollateralized Position Opening | Low | Solved - 04/15/2026 |
| Instant Upgrades With No Timelock or Pre-Upgrade Pause | Low | Solved - 04/16/2026 |
| Borrow Health Check Precedes Swap Deposit, Capping Effective Leverage at CF/(1-CF) | Low | Solved - 04/16/2026 |
| Expired Instance Storage Guard Allows Contract Re-Initialization | Low | Solved - 04/15/2026 |
| get_collateral_excl Omits Collateral Factor, Misleading External Callers | Low | Solved - 04/10/2026 |
| Missing Collateral/Base Asset Distinctness Check Enables Circular Self-Borrow | Low | Solved - 04/15/2026 |
| Missing Input Validation In verify_signatures Enables Budget Exhaustion And Multi-Signature Bypass | Low | Solved - 03/25/2026 |
| Missing enter_market Call Permanently Blocks MarginController Borrows | Low | Solved - 04/13/2026 |
| Permissionless claim() and Unbounded claim_all() Enable Reward DoS | Informational | Solved - 04/07/2026 |
| Borrow Index Saturation Can Corrupt Borrow Accounting | Informational | Solved - 03/29/2026 |
| Unchecked u128 to i128 Cast and Empty-Vec Panic in SwapAdapter | Informational | Solved - 04/13/2026 |
| Flawed Two-Phase Initialization Design Produces Dead Constructor Code And An Unreliable Re-Initialization Guard | Informational | Solved - 03/16/2026 |
| Two ReceiptVaults Sharing A DeFindex Pool Propagate Operational Risk | Informational | Solved - 04/07/2026 |
| Unvalidated Oracle Price Scale Causes Division-by-Zero DoS on Affected Assets | Informational | Solved - 04/15/2026 |
| exit_market Invokes Arbitrary Contracts Before Membership Validation | Informational | Solved - 04/10/2026 |
| require_auth() Placed After Input Validation And Test-Mode Admin Bypass Weakens JumpRateModel::initialize Security Posture | Informational | Solved - 03/27/2026 |
| Duplicate get_borrows_excl Calls Create Latent Solvency Bypass | Informational | Solved - 04/07/2026 |
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Halborn strongly recommends conducting a follow-up assessment of the project either within six months or immediately following any material changes to the codebase, whichever comes first. This approach is crucial for maintaining the project’s integrity and addressing potential vulnerabilities introduced by code modifications.
// Download the full report
Smart Contract Assessment
* Use Google Chrome for best results
** Check "Background Graphics" in the print settings if needed