StealthOSAll current reports

DogeOS contracts & wallet integration

Adversarial review

DogeOS ChikyuEVM / Groth16Browser wallet

Review date: 1 October 2026

Current remediation status — 12 October 2026

Finding-status verification against staging source, dated remediation records and targeted regression tests. Not a full re-audit or blanket deployment attestation.

D1 — Non-repeatable setup signatures can strand private notes

High · Reopened — partially mitigated

A same-browser fingerprint detects a changed signature, but the independent key backup/import flow and initial two-signature check were subsequently removed. The original recovery guarantee is no longer present.

Evidence / limits: Reproduced in the current wallet hook: the same account and payload with a different valid signature is rejected with its saved fingerprint, but after clearing storage it connects with a different spending seed. No real wallet vendor is alleged to have produced this signature variation. If the original signature cannot be reproduced or restored, access to the original notes can be lost. Closure requires recoverable key material independent of signature repeatability, or a separately reviewed equivalent design.

Changes affecting closure: privacy-frontend 063921d · privacy-frontend 0973d62

D2 — Reorg causes replay of stale transaction success

Medium · Remediated in source

Reconcile previously submitted and confirmed journal entries against canonical receipts; retain signed attempts and nonce claims so displaced transactions can be replayed safely.

Evidence / limits: Current DogeOS regressions cover canonical inclusion, displaced-envelope replay, noncanonical receipts and unresolved consumed nonces. The current policy permits subsequent work after canonical inclusion; it does not promise L1-finality waiting.

Remediation commits: stealthos-relayer 436239e · stealthos-relayer 9eae24e

Download current status for all 19 findings · Status data and checked revisions


Original dated report

The original text below is preserved as a historical record. Use the current-status addendum above for finding closure.

Download original dated source report (without current addendum)

DogeOS Chikyu adversarial fund-loss audit — 2026-10-01

Remediation update: Both source findings have been addressed in local frontend and relayer worktrees. See REMEDIATION.md for changes, regression results and rollout limits. The audit below describes the pre-fix behavior.

Scope and conclusion

This review covers the new /dogeos DogeOS Chikyu integration (chain ID 6281971): the browser's wallet/key derivation and JoinSplit V2 send/recovery paths, the EVM relayer's fee and submission journals, and the deployed-contract source and tests. It does not cover native Dogecoin UTXO transfers. Chikyu is configured as a testnet; no mainnet DogeOS deployment is enabled in the reviewed network record.

I found one high-severity conditional loss-of-access path and one medium-severity reorganization/reconciliation defect. I did not reproduce a contract-level unauthorized withdrawal or an automatic loss of vault funds. The high-severity path becomes irreversible if a non-deterministic wallet's first derived spending signature is lost after receiving notes. The reorg defect leaves funds in the pool in the reproduction, but falsely reports a completed withdrawal and blocks normal recovery.

Findings

D1 — High: non-deterministic wallet signatures can strand received notes

Location: privacy-frontend/src/base-app/hooks/useBaseWallet.ts:110-125, privacy-frontend/src/base-app/helpers/baseDerivation.ts:88-135, privacy-frontend/src/base-app/helpers/storage.ts:57-71,168-211.

connectWallet requests the derivation EIP-712 signature once, hashes the raw signature bytes into the spending seed, and marks the wallet connected. There is no determinism check. The DogeOS integration plan explicitly requires a two-signature D8 gate because embedded/MPC wallets may sign the same EIP-712 challenge non-deterministically (privacy-protocol/DOGEOS_MYDOGE_JOINSPLIT_PLAN.md:301-304). If the wallet produces signature A on initial connect and B after a restart, both valid for the same account and challenge, the application derives two different private accounts. A note delivered to A cannot be spent with B. Encrypted local caches and remote recovery records are also keyed to the signature-derived account; they do not restore A from B. The raw signature is kept in a React ref for the session, not as a recoverable wallet secret.

Reproduction: derivation-signature-reproduction.cjs constructs two distinct, valid EIP-712 signatures by the same test account for one DogeOS derivation challenge. ethers.verifyTypedData recovers the same account from both; the exact SHA-256-over-raw-signature operation used by baseDerivation.ts yields different seeds. It passes locally. This establishes the failure mode, not that any particular production MyDoge device currently signs this way. The MyDoge V3 device qualification matrix is still blank, including row 5 for signature determinism (privacy-frontend/docs/dogeos-mydoge-qualification.md).

Fix before accepting deposits: Fail closed when two signatures of the identical locally constructed challenge differ; preserve a signature fingerprint across sessions and reject changed derivation before exposing a receive address. Provide a durable, user-controlled recovery method for the original seed/signature, because a later wallet implementation change could otherwise strand already received notes. Qualify actual MyDoge injected, WalletConnect, and embedded/social wallet paths on devices.

D2 — Medium: an included withdrawal reorgs out but relayer replays stale success

Location: stealthos-relayer/src/relayer/evm-pool-v2/journal.js:117-139, stealthos-relayer/src/relayer/transaction-handler.js:1285-1323, stealthos-relayer/src/relayer/evm-submission-journal.js:87-148.

The settlement journal returns a cached confirmed row before checking a receipt. The transaction handler then returns status: "success" with its old hash. On Chikyu, the underlying submission journal permits the next signer nonce after canonical L2 inclusion, before L1 finality, and explicitly handles a later missing receipt as a reorg. These two journals disagree about what confirmed means.

Reproduction: run-relayer-reorg-reproduction.ps1 runs a test against the real handler: submit a DogeOS withdrawal with a canonical receipt while the finalized head lags; remove the receipt and reset the signer nonce to simulate a reorg; retry the same withdrawal. The handler returns the old hash as confirmed without reading the receipt or rebroadcasting. A second withdrawal is then blocked by the submission journal's unresolved nonce gate. The test passes and the source checkout remains unchanged.

Impact: The original withdrawal is not paid on the simulated canonical chain, yet the app can report payment complete. Its notes remain in the pool; the reproduction does not show irreversible loss or a double spend. The user can nevertheless act on a false payment confirmation, and normal retries do not clear the condition.

Fix: Treat a settlement as final only after the configured finality criterion and a canonical receipt check. For an included but unfinalized attempt, return a pending/reconciliation state and retain the durable signed bytes, nullifier claims, gas reservation, and signer nonce gate. On reorg, rebroadcast or reconcile the original signed attempt; never allocate a new nonce merely because a timeout elapsed. A retry with the same nullifiers but different calldata must locate the outstanding original attempt rather than opening a competing settlement.

Verification and limits

The contract tests and source review show useful protections, including exact ERC-20 deposit balance accounting and fail-closed proof/domain checks. Those checks do not mitigate D1 or D2, which occur in key derivation and the relayer state machine.