# Wrong design/implementation of freeTrial allows attacker to steal funds from the protocol

Unlock Protocol freeTrial keys can be shared to a second address then refunded in full, letting an attacker accumulate trial time and drain the lock's funds.

- Payout: Audit contest
- Severity: high
- Program: Unlock Protocol
- Found by: WatchPug
- Disclosed: 2022-04-20
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-11-unlock-findings/issues/188
- Library page: https://bugbountylibrary.com/r/c4%3A2021-11-unlock%3AH-02
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:chained vuln:accounting-error vuln:business-logic

**Target:** Unlock Protocol lock contract (purchase/shareKey/cancelAndRefund)
**Root cause:** cancelAndRefund refunds the full key price even after freeTrial time was transferred away via shareKey, so trial time can be consolidated onto one address and refunded.
**Steps:**
1. Configure lock: keyPrice=1 ETH, expirationDuration=360 days, freeTrialLength=31 days.
2. Alice calls `purchase()` to get a free-trial key.
3. Alice calls `shareKey(bob, 30 days)` to move trial time to Bob.
4. Alice calls `cancelAndRefund()` and receives a full refund.
5. Repeat 12 times so Bob accumulates ~360 days of transferred time.
6. Bob calls `cancelAndRefund()` and receives 1 ETH.
**How found:** Noticed freeTrial grants full refundability before trial ends and shareKey lets users transfer partial time, combining the two to consolidate trial time and refund it.
**Exploitation:** Attacker controls two addresses; repeatedly purchases free-trial keys on Alice, transfers the trial duration to Bob via shareKey, and refunds Alice's key for full price. Bob's accumulated time reaches expirationDuration, then Bob refunds for the full key price, extracting protocol funds.
**Escalation:** Repeat the purchase/share/refund cycle across many addresses to accumulate up to expirationDuration on one address and scale the drain.
**Insight:** When a protocol grants free/refundable time-bound assets, check whether that time is transferable and whether refund logic still returns full value after transfer; composability of share + refund is the bug.
