STRIDE Threat Model - Writz Protocol
Version: 0.1 (Draft) Date: June 2026 Scope: Phase 1 architecture (SPV contract + Writz Lend + P2WSH locking script + relayer) Methodology: Microsoft STRIDE (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege)System components in scope
Data flow diagram
Threat analysis - STRIDE
S - Spoofing (impersonating a legitimate entity)
S1: Attacker submits a fabricated SPV proof
Threat: An attacker constructs a fake SPV proof for a Bitcoin transaction that was never mined (or was mined with fewer confirmations than required) and submits it to the SPV contract. Mitigation:- The SPV contract validates the full header chain: each header’s
prev_block_hashmust equal SHA256d of the previous header. Fabricating a 6-deep valid chain requires solving 6 Bitcoin proof-of-work puzzles - infeasible at current difficulty. - The Merkle proof must correctly connect the transaction to the Merkle root embedded in the block header. Forging a valid Merkle proof without the actual transaction requires a SHA256 preimage attack - computationally infeasible.
- The raw transaction bytes are parsed on-chain; the txid is recomputed as SHA256d(raw_tx) and verified against the Merkle proof.
S2: Attacker impersonates the Writz protocol co-signing key
Threat: An attacker obtains the protocol private key and co-signs a fraudulent P2WSH release, draining all BTC collateral. Mitigation (today): The protocol key alone cannot move Bitcoin: the cooperative path also requires the user’s signature, so a stolen protocol key can at most refuse or delay releases, and the user’s time-lock exit (Path B) never needs it. Mitigation (planned): A 2-of-3 protocol side written into the P2WSH script, three keys held separately, so Bitcoin enforces the threshold natively and no single key can co-sign a release. Threshold ECDSA (MPC) is not planned. The signing policy, what the protocol signers can and cannot sign, will be published. Residual risk: MEDIUM with a single protocol key; LOW once the 2-of-3 protocol side ships.S3: Oracle price spoofing
Threat: An attacker manipulates the BTC/USD price fed to Writz Lend to artificially trigger liquidations or allow over-borrowing. Mitigation:writz-lendreads Reflector’s external-prices SEP-40 feed (CEX and DEX aggregation), which an on-chain flash loan cannot move. A price older than one hour is rejected, so a stale or unavailable feed blocks price-dependent calls rather than mispricing them.- Planned: a second source (Pyth, pull model) with a deviation guard, so a single bad feed is caught by the other. (RedStone dropped: Stellar is not in its supported-chain list. DIA parked: its documented testnet contract address returns “contract not found”. See
docs/research/oracle-design.md.) - TWAP (time-weighted average price) delays are considered as additional manipulation resistance.
T - Tampering (unauthorized data modification)
T1: Attacker tampers with the P2WSH redeem script
Threat: An attacker modifies the redeem script after the P2WSH address is generated to change the spending conditions. Mitigation: The P2WSH address commits to the SHA256 hash of the redeem script. The script is revealed only at spend time, and Bitcoin verifiesSHA256(revealed_script) == address_hash. Any modification to the script changes the hash and invalidates the address.
Residual risk: NONE - Bitcoin’s P2WSH construction is cryptographically binding.
T2: Attacker tampers with the Soroban contract state
Threat: An attacker modifies position data (debt amount, satoshi amount, status) directly in contract storage. Mitigation: Soroban’s execution model guarantees that contract storage can only be modified by the contract itself within its own execution context. The VM provides full isolation. Residual risk: NONE - Soroban VM isolation is a fundamental security property.T3: Attacker modifies the SPV proof data in transit
Threat: A man-in-the-middle attacker modifies the block headers or Merkle proof between the relayer and the user’s submission to the Soroban contract. Mitigation: The user submits the proof directly to the Soroban contract (the relayer is a data source, not an intermediary). The contract cryptographically validates all provided data. Even if the relayer provides modified data, the contract will reject it. Users can self-serve from any public Bitcoin data source. Residual risk: LOW - the user can always bypass the relayer entirely.R - Repudiation (denying having performed an action)
R1: Protocol denies co-signing a BTC release
Threat: A user repays their USDC loan but the protocol denies the repayment occurred and refuses to co-sign the P2WSH release. Mitigation:- Repayment is recorded on the Stellar blockchain - fully public and immutable. The
repay_fullevent is emitted at repayment time with the P2WSH scriptPubKey. - The user’s CLTV timelock provides a backstop: if the protocol refuses to co-sign, the user waits for the timelock to expire and recovers their BTC unilaterally.
- The timelock is set at loan origination block + loan duration + 7-day safety buffer - if the worst happens, the user is never permanently locked out.
R2: Keeper denies initiating a liquidation
Threat: The keeper claims to have initiated a liquidation that didn’t occur, or denies initiating one that did. Mitigation: Theliquidate() call and its result are recorded on Stellar’s ledger. The liquidate event includes the keeper’s address, the position txid, and the debt amount. All on-chain, all immutable.
Residual risk: NONE for on-chain record. Note: writz-lend uses a designated keeper, so keeper reliability is a concern - mitigated by the stale-keeper fallback: after 24 hours with no keeper liquidation or heartbeat, any caller may liquidate an undercollateralized position.
I - Information Disclosure (unauthorized access to private data)
I1: On-chain position amounts are public
Threat:writz-lend positions are plaintext: position amounts, debt sizes, health ratios, the depositor’s Stellar address and the Bitcoin deposit are visible on-chain. This exposes users to front-running and competitive analysis, as in any public lending market.
Mitigation: None in v1, by design. Writz v1 has no privacy layer, and this is disclosed in the user documentation. Privacy is being designed as a separate, opt-in edition with its own contracts, pool, audit and trusted-setup ceremony (see docs/how-it-works/privacy-edition.md); it is in progress, testnet only, not on the v1 mainnet plan and has no date.
Residual risk: HIGH for users who need confidential positions; accepted for v1.
E - Elevation of Privilege
E1: Attacker triggers liquidation on a healthy position
Threat: An attacker callsliquidate() on a position that is actually healthy, clearing the owner’s position against their will.
Mitigation:
liquidate()performs an on-chain collateral ratio check before proceeding:health_ratio = collateral_value / debt. If health ≥ liquidation threshold (120%), the call reverts withPositionHealthy.- Only the authorized keeper address can call
liquidate()while the keeper is active. After 24 hours of keeper inactivity anyone may call it, but the on-chain ratio check above still applies to every caller. liquidate()never moves BTC: the liquidator pays the USDC debt and receives a USDC bonus from the reserve.
E2: Attacker uses an undisclosed reentrancy exploit to drain the USDC pool
Threat: A malicious USDC token contract or cross-contract call enables reentrancy, allowing multiple withdrawals from a single repayment. Mitigation:- Soroban does not support EVM-style reentrancy: all contract calls are sequential within a transaction and state changes are applied atomically.
- The
repay()function updates internal state (debt, status) before callingtoken.transfer()- a checks-effects-interactions pattern.
E3: Attacker exploits integer overflow in the interest rate model
Threat: An attacker crafts a deposit or borrow scenario that causes integer overflow in the kinked interest rate calculation or the collateral ratio check. Mitigation:- All financial math uses Rust’s
i128(128-bit signed integer), providing sufficient range for all realistic BTC and USDC amounts. saturating_mulandsaturating_addare used throughout the rate model - overflow silently caps rather than wrapping.- The Soroban compilation profile has
overflow-checks = truein release mode - integer overflow panics rather than wrapping. - Unit tests cover the rate model at boundary values (U=0%, U=75%, U=100%, U>100%).
Residual risk summary
Security priorities for audit
The external audit before mainnet should focus on, in priority order:- SPV verification correctness - is the SHA256d implementation correct? Does header chain validation correctly prevent header substitution attacks?
- Interest rate model overflow - are there edge cases in the kinked rate formula that could cause incorrect interest calculation at extreme values?
- Cross-contract call trust - can a malicious contract be registered as the SPV contract to bypass deposit verification?
- Protocol key security - the 2-of-3 protocol signers, their published signing policy, and key recovery procedures
- ZK circuit soundness - not part of v1; the privacy edition’s circuits get their own audit before that edition launches
Last updated: June 2026 - v0.1 draft. Full revision planned before the external audit.