# Unexecutable proposals when Actions.MigrateKernel is not last instruction

INSTR.sol only enforces ChangeExecutor as last instruction; a MigrateKernel followed by DeactivatePolicy changes kernel mid-proposal, making later onlyKernel calls fail and the proposal unexecutable.

- Payout: Contest reward
- Severity: medium
- Program: Olympus DAO
- Credited: Lambda
- Disclosed: 2022-10-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-08-olympus-findings/issues/51
- Library page: https://bugbountylibrary.com/r/c4%3A2022-08-olympus%3AM-27
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:governance

**Target:** INSTR.sol instruction executor / governance proposal module
**Root cause:** MigrateKernel updates the policy's kernel reference immediately, so any subsequent instruction calling an onlyKernel-gated function (e.g. DeactivatePolicy's setActiveStatus) is authorized against the new kernel and reverts. Only ChangeExecutor was constrained to last position.
**Steps:**
1. Build a proposal with instructions `[MigrateKernel, DeactivatePolicy]`.
2. Execute proposal; MigrateKernel sets policy.kernel to new kernel.
3. DeactivatePolicy calls setActiveStatus on the policy, which has onlyKernel modifier checking msg.sender == kernel.
4. Call reverts because caller is old kernel, so the whole proposal is unexecutable.
**How found:** Code review of INSTR.sol: noticed the existing last-position check for ChangeExecutor and reasoned the same ordering hazard applies to MigrateKernel since it mutates kernel state used by onlyKernel authorization.
**Insight:** When a governance executor special-cases one state-mutating instruction to be last, audit every other instruction that mutates authorization-relevant state (kernel, owner, admin) for the same ordering hazard.
