# Re-triggering the canOffboard[term] flag to bypass the DAO vote of the lending term offboarding mechanism

Stale offboarding poll lets an attacker re-trigger canOffboard[term] after cleanup, forcing a re-onboarded lending term to offboard without a DAO vote.

- Payout: Contest reward
- Severity: medium
- Program: Ethereum Credit Guild
- Credited: serial-coder
- Disclosed: 2024-02-22
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-12-ethereumcreditguild-findings/issues/1141
- Library page: https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AM-06
- Tags: domain:web3 impact:dos impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:incomplete-fix technique:source-review vuln:access-control vuln:business-logic vuln:governance

**Target:** LendingTermOffboarding governance contract (supportOffboard/offboard/cleanup)
**Root cause:** cleanup() resets canOffboard[term] but the offboarding poll remains valid for ~7 days; supportOffboard() re-sets canOffboard[term] without checking whether the term was already cleaned up, and offboard() never clears the flag or poll state.
**Steps:**
1. Bob proposes offboard and votes; supportOffboard sets canOffboard[term]=true; offboard() removes gauge.
2. Loans repaid; cleanup() runs, resetting canOffboard[term]=false while poll still within POLL_DURATION_BLOCKS.
3. Attacker calls `supportOffboard(snapshotBlock, term)` with any guild weight; since _weight+userWeight >= quorum, canOffboard[term] is set true again.
4. Wait arbitrarily long; term is re-onboarded via proposeOnboard + timelock.
5. Attacker calls `offboard(term)`; require(canOffboard[term]) passes, gauge removed, PSM redemptions paused, term forced offboard.
**How found:** Code reading of the offboarding lifecycle: noticed cleanup() resets canOffboard but the poll's ~7-day window persists, and supportOffboard() re-sets the flag without checking term state, so a stale poll can be re-voted after cleanup.
**Exploitation:** Attacker needs only a tiny guild balance delegated before the snapshot and to act while the original poll is still live. After re-triggering the flag they wait months, let the term be re-onboarded and issue loans, then call offboard() to force immediate offboarding, calling all loans and pausing PSM redemptions, bypassing the DAO vote.
**Escalation:** Forced offboarding calls all outstanding loans; failed bids notify term loss, slashing SurplusGuildMinter stakers' CREDIT principal and GUILD rewards, and blocks new loans/voting on the term.
**Insight:** When a cleanup/reset function clears a derived flag, check whether the underlying poll/proposal state that can regenerate that flag is also invalidated; stale proposal windows are a recurring governance bypass.
