# Wrong actor forwarding bricks token upgrade flows

K2 configurator forwards the admin EOA instead of its own contract address to the router, so token implementation upgrades always revert Unauthorized.

- Payout: Contest reward
- Severity: medium
- Program: K2
- Credited: v12
- Disclosed: 2026-08-20
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2026-04-k2#m-34
- Library page: https://bugbountylibrary.com/r/c4%3A2026-04-k2%3AM-34
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:rust technique:source-review vuln:access-control vuln:business-logic

**Target:** Soroban/Rust pool-configurator and kinetic-router contracts (update_atoken, update_variable_debt_token, update_token_implementation)
**Root cause:** update_atoken and update_variable_debt_token authenticate the pool admin locally but forward that admin EOA as caller to the router, while KineticRouter.update_token_implementation authorizes via validate_pool_configurator expecting the configurator contract address.
**Steps:**
1. Call `PoolConfiguratorContract::update_atoken` as the pool admin.
2. Configurator validates admin, then invokes router passing the admin EOA as caller.
3. Router reaches `update_token_implementation`, which runs `storage::validate_pool_configurator(env, caller)`.
4. Caller is the admin EOA, not the stored configurator address, so it reverts Unauthorized.
5. Repeat with `update_variable_debt_token`; same failure. Fix: forward `env.current_contract_address()`.
**How found:** Code review of the configurator-to-router handoff: compared the actor passed across the contract boundary against the router's authorization check, spotting the mismatch between admin EOA and configurator contract address.
**Insight:** In cross-contract flows, trace which identity (EOA vs contract address) each downstream authorization check expects; a locally-correct admin check can still fail if the forwarded caller identity differs from the stored authorizer.
