# Deactivate function can be bypassed

Shelter.activate can be re-called after grace period to reset the timestamp, letting a malicious client deactivate and drain all saved tokens.

- Payout: Audit contest
- Severity: medium
- Program: Concur Finance
- Found by: csanuragjain
- Disclosed: 2022-05-24
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-02-concur-findings/issues/28
- Library page: https://bugbountylibrary.com/r/c4%3A2022-02-concur%3AM-17
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Shelter.sol token shelter contract
**Root cause:** activate() unconditionally overwrites activated[_token] with block.timestamp, so re-activating an already-activated token resets the grace-period clock and re-opens the deactivate window.
**Steps:**
1. Client calls `activate(tokenX)`; activated[tokenX] = now, savedTokens[tokenX] = balance.
2. Wait until `activated[tokenX] + GRACE_PERIOD < block.timestamp`; `deactivate(tokenX)` now reverts with "too late".
3. Client calls `activate(tokenX)` again, resetting activated[tokenX] to current timestamp.
4. Client immediately calls `deactivate(tokenX)`, which now passes the grace check and transfers all token balance to the client.
**How found:** Code reading of Shelter.sol: noticed the deactivate guard depends on activated[_token] + GRACE_PERIOD, and that activate lacks a check preventing re-activation, so the timestamp can be refreshed at will.
**Exploitation:** A malicious client waits past the grace period, re-invokes activate to reset the timestamp, then calls deactivate to sweep the shelter's entire token balance to itself, rugging all other depositors.
**Insight:** When a time-window guard reads a timestamp that a separate permissioned function can rewrite, check whether that function can be re-invoked to reset the clock; state-machine transitions like activate should be one-shot (require activated[_token]==0).
