Security disclosure
skUSD admin status: parked-solo-admin
skUSD is a live ERC-4626 wrapper for kUSD that you can deposit into today from app.kerne.fi. The vault is functional, source verified, and accepts deposits. However, its admin and strategist roles are currently parked on a single Trezor wallet pending rotation to the 2-of-3 Safe at the next signer quorum. This page is the canonical disclosure of exactly what that means, what the on-chain exit guarantee is, and how the rotation will be executed.
Last updated: May 14, 2026
What is parked on a single key right now
The skUSD contract at 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 was deployed on Base mainnet on 2026-05-11 (tx 0x03270583…, block 45,876,491). At deploy time, two AccessControl roles were granted to Scofield's Trezor wallet at 0x14f04cE02f35B29Af564A98544dD7e2393993946:
- DEFAULT_ADMIN_ROLE can grant and revoke other roles, including granting itself to a new address.
- STRATEGIST_ROLE can call distributeYield(amount) to push kUSD into the vault (raises share price for all holders) and sweepDonations(to) to recover untracked donations.
The 2-of-3 Kerne Safe at 0x52d3E450bA6c299B1B07298F1E87DD74732D4877 currently holds neither role on skUSD. The bot strategist wallet at 0x09a2780ac8Be6D5d2d1F85A8D92b09D40C9CA37e also holds neither role on skUSD yet.
What this means in practice
The strategist key controls the upward path of skUSD share price. Specifically, a compromised strategist key could call distributeYield() with zero or attacker-controlled kUSD donations to inflate the ledger arbitrarily, or could grant new roles to additional addresses via DEFAULT_ADMIN_ROLE.
The skUSD source includes two structural defenses that bound the blast radius even under a compromised key. First, the vault tracks assets via an internal _trackedAssets ledger rather than balanceOf(this), so a direct ERC-20 donation cannot inflate share price without an authenticated distributeYield() call. Second, the contract defines _decimalsOffset() = 6, adding 106 virtual shares so the classic first-depositor share-rounding attack requires an economically prohibitive donation. The full source is at Sourcify (full match) and Blockscout.
The exit guarantee that does not depend on skUSD admin
skUSD is a wrapper. The underlying asset is kUSD at 0x5C2EfdF0D8D286959b42308966bc2B97f5680AA3. kUSD is administered by the 2-of-3 Kerne Safe and is mintable and redeemable 1:1 against USDC via the live PSM at 0xFf3025ec18e301855aB0f36Ec6ECa115a29A5Fbc. Anyone holding kUSD can redeem it for USDC via the PSM at any time, regardless of skUSD state.
skUSD redemption (the redeem() path on the vault) is permissionless and instant. There is no withdrawal cooldown coded on skUSD. Each share holder can burn their shares for their pro-rata kUSD entitlement at any time, then redeem that kUSD for USDC at the PSM.
The maximum exposure of any individual skUSD depositor is therefore bounded by the share-price math the contract enforces, not by what the parked admin can do to the kUSD asset itself.
The Safe rotation plan
The full rotation sequence is documented in the canonical deployments registry at deployments/8453.json :: skUSDStatus.pendingRotation and consists of five Trezor-signed transactions executed in order at the next 2-of-3 signer convening:
- Trezor calls skUSD.grantRole(DEFAULT_ADMIN_ROLE, Safe) so the Safe is admin alongside the Trezor.
- Trezor calls skUSD.grantRole(STRATEGIST_ROLE, bot) so the bot strategist key can call distributeYield() on schedule.
- Trezor calls skUSD.renounceRole(STRATEGIST_ROLE, Trezor) so the single key no longer has yield-distribution authority.
- Trezor calls skUSD.renounceRole(DEFAULT_ADMIN_ROLE, Trezor). This transaction is irreversible and is the canonical moment the parked-solo-admin posture ends.
- Bot calls skUSD.distributeYield(small_test_amount) as a smoke-test that the new role topology works end-to-end.
Once step 4 lands on-chain, this page will be updated with the rotation transaction hashes and the disclosure status will move from PARKED_SOLO_ADMIN to SAFE_ADMIN. The MintWidget on app.kerne.fi will drop its inline admin-posture callout the same day.
Why we shipped the widget before rotation
kUSD has been mintable via the live PSM since 2026-04-16, and the protocol's 16% live APY is the yield that flows through skUSD, not through holding raw kUSD. Without a live skUSD widget, every kUSD minter is sitting on principal that earns Opal Genesis fragments but not the published basis yield. We considered keeping the Stake tab disabled until rotation lands, and concluded that the right tradeoff for depositors who understand the disclosure is to ship the live deposit path now, document the admin posture honestly, and ship rotation as soon as the signer quorum convenes.
The alternative (waiting) would have meant every visitor who minted kUSD between now and rotation holds non-yielding principal while the underlying basis trade earns. Yes, those visitors could wait for rotation before depositing into skUSD, but in practice that asks each visitor to track a multi-signer governance event they have no visibility into. Shipping with disclosure puts the decision in their hands instead of ours.
On-chain proofs you can verify yourself
Every claim on this page is verifiable with public RPC reads. The relevant cast commands against any Base RPC:
# Confirm Trezor holds DEFAULT_ADMIN_ROLE on skUSD (should return true today) cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 \ "hasRole(bytes32,address)(bool)" \ 0x0000000000000000000000000000000000000000000000000000000000000000 \ 0x14f04cE02f35B29Af564A98544dD7e2393993946 \ --rpc-url https://mainnet.base.org # Confirm Safe does NOT yet hold DEFAULT_ADMIN_ROLE on skUSD (should return false) cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 \ "hasRole(bytes32,address)(bool)" \ 0x0000000000000000000000000000000000000000000000000000000000000000 \ 0x52d3E450bA6c299B1B07298F1E87DD74732D4877 \ --rpc-url https://mainnet.base.org # Confirm skUSD underlying asset is kUSD (sanity check) cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 "asset()(address)" \ --rpc-url https://mainnet.base.org # Confirm kUSD is administered by the 2-of-3 Safe cast call 0x5C2EfdF0D8D286959b42308966bc2B97f5680AA3 \ "hasRole(bytes32,address)(bool)" \ 0x0000000000000000000000000000000000000000000000000000000000000000 \ 0x52d3E450bA6c299B1B07298F1E87DD74732D4877 \ --rpc-url https://mainnet.base.org
Audit references
skUSD was covered by the 2026-05-08 adversarial audit (36 Critical / 51 High / 51 Medium / 37 Low / 26 Info across all 80 Kerne contracts). The math hardening commit c082246f switched skUSD's totalAssets() from balanceOf(this) to the internal _trackedAssets ledger and added sweepDonations() so donated assets land outside the share-pricing surface. Two source-only findings remain open on skUSD: the _decimalsOffset = 6 is still attackable at approximately $1M cost (partly mitigated by the ledger), and distributeYield() has no upper bound and no event emission. Both are tracked at /security/findings-tracker.