External audit
The Hexens audit of Kerne, in full
Final report published July 31, 2026. Page last updated August 2, 2026.
Hexens reviewed kUSD, skUSD, KUSDPSM, KerneVault, and esKERNE, each pinned to commit 0912c870, and published its final report on July 31, 2026. It found 10 issues: none critical, 2 high, 2 medium, 4 low and 2 informational. 8 were fixed and 2 were acknowledged without a code change. All 10 are in KerneVault.
Read that with the next sentence attached, because it is the one that matters. An audit reviews a commit, not a chain. The live KerneVault was deployed on June 16, 2026 from source older than the reviewed commit, so every vault finding below is open on the bytecode running today. That vault holds no user funds, has never issued a share, and deposits into it are closed on chain until the remediated build is deployed and verified.
What the document is
| Reviewer | Hexens, review led by Trung Dinh, Lead Security Researcher. Kerne paid for the engagement, which is true of essentially every audit in this industry and is rarely said out loud. |
|---|---|
| Report | hexens-kerne-protocol-final-2026-07-31.pdf (29 pages, 8,269,537 bytes), committed verbatim and unedited in the public contract registry. |
| SHA-256 | 655e7126030c750e9d58f2ab30b58215ce604942f06997d5c01532d6f687a4ca |
| Commit reviewed | 0912c870a89f1fa707f69c60fc05c05ea85e2fa8, frozen before fieldwork began so the reviewed code could not move underneath the reviewers mid engagement. |
| Scope | Five contracts: kUSD, skUSD, KUSDPSM, KerneVault, and esKERNE. The report names each one at the frozen commit. |
| Remediation commit | 98f29e55, named in the report's own scope section. |
| Timeline | Fieldwork started July 13, 2026. Initial report July 20, 2026. Revision received July 21, 2026. Final report July 31, 2026. |
The hash is there so you do not have to trust the filename. Download the PDF, hash it, and confirm you are reading the same bytes Kerne published. The whole audits directory, including the earlier independent researcher review and the deployed-versus-source map, is at contracts-public/audits.
One note on the report's own scope links: they point at the private development repository, so they will not open for you. The commit hash above is the checkable fact, and the mirrored source is public at kerne-protocol/contracts-public.
What it found
10 findings in total. 8 fixed, 2 acknowledged without a code change. On the re-test the report records that all identified issues were either remediated or acknowledged by the development team and subsequently verified by its auditors.
Every one of the 10 is in KerneVault, the contract that holds assets and does the accounting. kUSD, skUSD, the peg stability module and esKERNE drew none between them. A review finding nothing in a contract is evidence, not proof: the honest reading of a zero is that a competent team looked and did not find something. One further caveat we would want made if this were someone else's page: both high findings concern the escrow token's forfeiture mechanism, and the report files them against the vault because that is where the offending code sits. Zero findings filed against esKERNE is not the same as the escrow design going unexamined.
Every finding
Ids, titles, severities and dispositions are the report's own. Each row links to our response below, and each response has a stable anchor so a single finding can be linked on its own.
| ID | Title | Severity | Disposition |
|---|---|---|---|
| KERNE1-4 | Transferable kLP shares can separate withdrawal and esKERNE forfeiture identities | High | Acknowledged |
| KERNE1-5 | esKERNE forfeiture can be bypassed by gas-starving the best-effort forfeit call | High | Fixed |
| KERNE1-7 | totalAssets silently under-reports NAV when the verification node call fails | Medium | Fixed |
| KERNE1-9 | _checkCRCircuitBreaker should be applied to captureFounderWealth | Medium | Fixed |
| KERNE1-2 | Unable to update offChainAssets when offChainAssets == 0 and _offChainAssetsBootstrapped == true | Low | Fixed |
| KERNE1-3 | maxTotalAssets check overestimates deposited assets | Low | Fixed |
| KERNE1-10 | _checkCRCircuitBreaker should pause the protocol when the collateral ratio exceeds SAFE_CR_THRESHOLD | Low | Acknowledged |
| KERNE1-11 | Withdrawal Requests Are Not Bound to the Share Price at Request Time | Low | Fixed |
| KERNE1-6 | Redundant _checkSolvency() function in KerneVault | Informational | Fixed |
| KERNE1-8 | Redundant extracted variable in captureFounderWealth function | Informational | Fixed |
Acknowledged means Kerne agreed the finding is valid and did not ship a code change. It is listed here with the same weight as the 8 that were fixed, and the report carries Kerne's written reasoning on both.
Our response, finding by finding
Written by Kerne, not by the auditor. The full narrative version, including the correction we sent the auditor about our own first answer, is in the response post. Where this page summarises a finding in plain language, the report's own text governs.
Transferable kLP shares can separate withdrawal and esKERNE forfeiture identities
Acknowledged rather than patched, and the reasoning is the part worth reading. The obvious fix is to make vault shares non transferable while the forfeiture mechanism is set. We implemented that, and our own adversarial re-review caught what it does: those shares are the collateral asset for kUSD borrowing positions, so blocking wallet to wallet transfers would have broken collateral deposits and made underwater positions impossible to liquidate, because a liquidator seizing collateral is itself a share transfer. The second obvious fix, firing forfeiture whenever shares move, would slash a user who merely posted shares as collateral. A correct fix has to tell an economic exit apart from a collateralization or liquidation movement, which is a design decision rather than a patch. What makes the wait acceptable: the forfeiture mechanism is inert on chain today, nothing has ever been emitted for it to act on, and the token it would redeem into is retired. It will not be enabled until the ownership versus forfeiture binding is designed and re-tested.
esKERNE forfeiture can be bypassed by gas-starving the best-effort forfeit call
Fixed with a gas floor. Before the forfeiture call the contract now requires a minimum amount of gas remaining, and reverts the whole withdrawal if it is not there. The outcome set goes from three possibilities to two: either forfeiture runs, or the withdrawal fails. The quiet third option, where the withdrawal succeeds and the penalty is skipped, is gone. Ordinary full gas withdrawals are unaffected.
totalAssets silently under-reports NAV when the verification node call fails
Fixed. When the verification node call failed, the vault's total assets reading silently dropped the off-chain buckets instead of falling back to the full formula, so a transient outage briefly made the vault look poorer than it was, and anyone who could trigger that outage on demand had a cheap mint and redeem window. The fallback path now returns the complete figure.
_checkCRCircuitBreaker should be applied to captureFounderWealth
Fixed. The function that captures founder revenue reduced assets without arming the collateral ratio circuit breaker, unlike the three other paths that reduce assets. It arms it now.
Unable to update offChainAssets when offChainAssets == 0 and _offChainAssetsBootstrapped == true
Fixed, and this one was our fault in a specific way. In May 2026 we hardened the vault's rate limiting so a strategist could not zero a bucket and then restore it to bypass the per update change cap. That hardening introduced this bug: once a bucket legitimately sat at zero, the rate limit maths made every non-zero write revert forever, with no path back up. We did not find it, Hexens did. The fix replaces the silent failure with an explicit error that names the recovery path, a deliberate multisig gated re-seed rather than something the strategist can do alone, so the original bypass stays closed.
maxTotalAssets check overestimates deposited assets
Fixed. The deposit cap counted the deposit fee as though it stayed in the vault, so deposits were turned away slightly early. The check now excludes the fee.
_checkCRCircuitBreaker should pause the protocol when the collateral ratio exceeds SAFE_CR_THRESHOLD
Acknowledged rather than patched. The recommendation was to pause the vault when the collateral ratio rises above the safe threshold, on the theory that an inflated ratio signals manipulation. A healthy delta neutral vault routinely runs above that threshold in ordinary operation, so a hard pause there would halt the vault on good days rather than only on bad ones, and picking a sensibly high bound is a tuning question we would rather resolve deliberately. In the meantime the bucket updates that could inflate the ratio are rate limited and cooldown gated, withdrawals route through a request queue and can never be same block with an inflation, and the KERNE1-11 fix caps the payout at the request time snapshot, which removes the profit from the scenario the finding describes. We told the auditor we are open to adding a conservative upper bound alert as a follow up.
Withdrawal Requests Are Not Bound to the Share Price at Request Time
Fixed. A withdrawal claim is now bound to the share price at the moment the withdrawal was requested, rather than settling at whatever the price is when the claim lands.
Redundant _checkSolvency() function in KerneVault
Fixed in the remediation commit. An internal function that nothing called.
Redundant extracted variable in captureFounderWealth function
Fixed in the remediation commit. A local variable that duplicated a value already in hand.
What this report does not say
Read this part before you read the table above.
- An audit reviews a commit, not a chain. The reviewed commit is 0912c870. The remediation commit is 98f29e55. Neither is the bytecode running in the live KerneVault, which was deployed on June 16, 2026 from earlier source. The vault findings above are open against it. The full map, with commands to check every claim yourself, is at /security/deployed-vs-source.
- A completed audit is not a guarantee of safety. We will not describe this code as passed, clean, secure or safe, now or after any future audit. The report does not use those words either.
- The off-chain hedge leg was not in scope. It runs on a single venue and is self reported rather than independently re-derivable on chain, and a smart contract review cannot attest it. Neither our operational security nor our key custody practice beyond what the contracts encode was in scope.
- 2 findings were acknowledged, not fixed. They are listed above with the same weight as the 8 that were fixed.
Everything else we disclose is exactly where it was before this report. The open gaps we know about are listed at /legible, the audit diary and the earlier internal adversarial reviews are at /security/audits, and the bug bounty and findings-response protocol are unchanged at /security.
Finding counts, severities and dispositions are as stated in the published Hexens report. Nothing here is investment advice and nothing here is an offer. An external audit is a review of specific contracts at a specific commit and is not a guarantee of safety, a solvency opinion, or a statement about the off-chain leg of the design.