Summary
eth_sign and eth_signTypedData in the JSON-RPC backend skip the AllowInsecureUnlock check that the other four account-related RPCs enforce. When an operator runs with --json-rpc.allow-insecure-unlock=false expecting account-related signing over HTTP to be blocked, these two endpoints still produce signatures from the loaded keyring.
Vulnerable code (on main HEAD 9a516a34d)
rpc/backend/sign_tx.go:124-142 — Backend.Sign() accesses b.ClientCtx.Keyring.SignByAddress with no AllowInsecureUnlock guard.
rpc/backend/sign_tx.go:147-168 — Backend.SignTypedData() same pattern, no guard.
For comparison, the correctly guarded endpoints all open with if !b.Cfg.JSONRPC.AllowInsecureUnlock { return ..., fmt.Errorf("account unlock with HTTP access is forbidden") }:
rpc/backend/sign_tx.go:22-27 — SendTransaction()
rpc/backend/node_info.go:34 — Accounts()
rpc/backend/node_info.go:84 — SetEtherbase()
rpc/backend/node_info.go:225 — ListAccounts()
Fix
A fix already exists on the remote branch origin/worktree-fix-eth-sign-insecure-unlock (commit d8ea64168, dated 2026-03-24) that adds the four-line guard to both functions. Merge that branch (or land an equivalent two-function patch) plus unit tests asserting the error response when the flag is false. Also worth adding a sweep test or linter check that asserts every Backend method touching b.ClientCtx.Keyring.Sign* either has the AllowInsecureUnlock guard or an explicit comment justifying why it does not, so the next account-related RPC we add does not repeat the omission.
Severity / impact
Classified as Low on HackenProof. eth_sign returns a \x19Ethereum Signed Message-prefixed signature only useful for off-chain auth flows; eth_signTypedData can produce EIP-712 signatures usable for ERC-2612 permit-drain or off-chain marketplace orders, but the realistic fund-extraction path requires four operator-side preconditions to converge (flag set to false against the default true, funded EVM key loaded into validator keyring against standard operator practice, EIP-712-eligible assets controlled by that key, and a publicly reachable RPC port). The realistic population on ZetaChain mainnet satisfying all four is plausibly zero. The fix ships as code hygiene rather than incident response.
Source
HackenProof report: https://dashboard.hackenproof.com/manager/companies/zetachain/zetachain-blockchain-software/reports/ZCNode-284
Summary
eth_signandeth_signTypedDatain the JSON-RPC backend skip theAllowInsecureUnlockcheck that the other four account-related RPCs enforce. When an operator runs with--json-rpc.allow-insecure-unlock=falseexpecting account-related signing over HTTP to be blocked, these two endpoints still produce signatures from the loaded keyring.Vulnerable code (on
mainHEAD9a516a34d)rpc/backend/sign_tx.go:124-142—Backend.Sign()accessesb.ClientCtx.Keyring.SignByAddresswith noAllowInsecureUnlockguard.rpc/backend/sign_tx.go:147-168—Backend.SignTypedData()same pattern, no guard.For comparison, the correctly guarded endpoints all open with
if !b.Cfg.JSONRPC.AllowInsecureUnlock { return ..., fmt.Errorf("account unlock with HTTP access is forbidden") }:rpc/backend/sign_tx.go:22-27—SendTransaction()rpc/backend/node_info.go:34—Accounts()rpc/backend/node_info.go:84—SetEtherbase()rpc/backend/node_info.go:225—ListAccounts()Fix
A fix already exists on the remote branch
origin/worktree-fix-eth-sign-insecure-unlock(commitd8ea64168, dated 2026-03-24) that adds the four-line guard to both functions. Merge that branch (or land an equivalent two-function patch) plus unit tests asserting the error response when the flag isfalse. Also worth adding a sweep test or linter check that asserts everyBackendmethod touchingb.ClientCtx.Keyring.Sign*either has theAllowInsecureUnlockguard or an explicit comment justifying why it does not, so the next account-related RPC we add does not repeat the omission.Severity / impact
Classified as Low on HackenProof.
eth_signreturns a\x19Ethereum Signed Message-prefixed signature only useful for off-chain auth flows;eth_signTypedDatacan produce EIP-712 signatures usable for ERC-2612 permit-drain or off-chain marketplace orders, but the realistic fund-extraction path requires four operator-side preconditions to converge (flag set to false against the defaulttrue, funded EVM key loaded into validator keyring against standard operator practice, EIP-712-eligible assets controlled by that key, and a publicly reachable RPC port). The realistic population on ZetaChain mainnet satisfying all four is plausibly zero. The fix ships as code hygiene rather than incident response.Source
HackenProof report: https://dashboard.hackenproof.com/manager/companies/zetachain/zetachain-blockchain-software/reports/ZCNode-284