fix: add AllowInsecureUnlock guard to eth_sign and eth_signTypedData#4562
fix: add AllowInsecureUnlock guard to eth_sign and eth_signTypedData#4562CharlieMc0 wants to merge 4 commits intodevelopfrom
Conversation
Sign() and SignTypedData() bypass the AllowInsecureUnlock config flag, allowing JSON-RPC callers to use the node as a signing oracle even when the operator explicitly disables insecure unlock. Add the same guard already present in SendTransaction() to both methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis change adds a security configuration guard to the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
rpc/backend/sign_tx_test.go (1)
156-164: Consider asserting the specific rejection error, not justerr != nil.Right now, any unrelated error would pass these cases. Adding an expected error string/type per case will make the tests stricter and less brittle.
Proposed test tightening
testCases := []struct { name string registerMock func() fromAddr common.Address inputBz hexutil.Bytes + expErrSubstr string expPass bool }{ { "fail - insecure unlock not allowed", func() { s.backend.Cfg.JSONRPC.AllowInsecureUnlock = false }, from, nil, + "account unlock with HTTP access is forbidden", false, }, @@ if tc.expPass { ... } else { s.Require().Error(err) + if tc.expErrSubstr != "" { + s.Require().Contains(err.Error(), tc.expErrSubstr) + } }Also applies to: 216-224
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@rpc/backend/sign_tx_test.go` around lines 156 - 164, The test case that flips s.backend.Cfg.JSONRPC.AllowInsecureUnlock = false (in rpc/backend/sign_tx_test.go) currently only asserts err != nil; update the test table entries (including the similar cases around lines 216-224) to include an expected error value or substring and replace the generic non-nil check with an assertion that the returned error matches that expected error (by comparing error type or using strings.Contains(err.Error(), expectedErrSubstring) or errors.Is for concrete sentinel errors), referencing the failing case entry that sets AllowInsecureUnlock and the test helper that invokes the sign/authorization path to validate the specific rejection error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@rpc/backend/sign_tx_test.go`:
- Around line 156-164: The test case that flips
s.backend.Cfg.JSONRPC.AllowInsecureUnlock = false (in
rpc/backend/sign_tx_test.go) currently only asserts err != nil; update the test
table entries (including the similar cases around lines 216-224) to include an
expected error value or substring and replace the generic non-nil check with an
assertion that the returned error matches that expected error (by comparing
error type or using strings.Contains(err.Error(), expectedErrSubstring) or
errors.Is for concrete sentinel errors), referencing the failing case entry that
sets AllowInsecureUnlock and the test helper that invokes the sign/authorization
path to validate the specific rejection error.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 132dc9e4-ab22-47a7-9244-0a80f3bd600c
📒 Files selected for processing (2)
rpc/backend/sign_tx.gorpc/backend/sign_tx_test.go
ws4charlie
left a comment
There was a problem hiding this comment.
lgtm. The code style commented by Greptile have low priority but might worth fixing.
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
|
@cursor update the changelog to incldue this change |
|
I've updated the changelog to include this PR. The entry has been added to the "Fixes" section under "Release ReForge" at line 26: The change has been committed and pushed to the |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-authored-by: Charlie McCowan <CharlieMc0@users.noreply.github.com>


Summary
AllowInsecureUnlockcheck toSign()andSignTypedData()inrpc/backend/sign_tx.go, consistent with the existing guard inSendTransaction()json-rpc.allow-insecure-unlock=false, these methods now correctly reject signing requests instead of acting as an open signing oracleTest plan
go test -tags=test ./rpc/backend/... -run TestBackendTestSuite/TestSign— all pass including new guard testgo test -tags=test ./rpc/backend/... -run TestBackendTestSuite/TestSignTypedData— all pass including new guard test🤖 Generated with Claude Code
Note
Medium Risk
Changes signing RPC behavior to hard-fail when
json-rpc.allow-insecure-unlockis disabled, which is security-sensitive and could break clients that relied on the previous permissive behavior.Overview
Prevents the JSON-RPC server from acting as an open signing oracle.
Sign(eth_sign) andSignTypedData(eth_signTypedData) now enforce theCfg.JSONRPC.AllowInsecureUnlockgate, returning an error when insecure unlock is disabled (matchingSendTransaction).Tests are extended to cover the new rejection path for both signing methods when
AllowInsecureUnlock=false.Written by Cursor Bugbot for commit d8ea641. Configure here.
Greptile Summary
This PR closes a security gap where
eth_sign(Sign()) andeth_signTypedData(SignTypedData()) were acting as open signing oracles even whenjson-rpc.allow-insecure-unlock=false, whileSendTransaction()already had the guard in place. The fix adds the missingAllowInsecureUnlockcheck to both methods, making all three functions consistent in their access control.Sign()andSignTypedData()inrpc/backend/sign_tx.gonow return early with an error whenAllowInsecureUnlock=false, before any keyring access.sign_tx_test.goverify the reject-when-disabled behavior for both methods; test isolation is correct sinceSetupTest()resets the flag totruebefore each case.AllowInsecureUnlockremainstrue(defined inserver/config/config.go), meaning the change is non-breaking for existing deployments. Operators who had already set the flag tofalsewill now correctly haveeth_signandeth_signTypedDatablocked.fmt.Errorfis used without format verbs in the new error returns —errors.Newwould be more idiomatic, and is consistent with standard Go best practices.Confidence Score: 5/5
SendTransaction(). Tests are well-structured and correctly isolated. No existing behavior is altered for the default (AllowInsecureUnlock=true) configuration. The only finding is a minorfmt.Errorf→errors.Newstyle suggestion.Important Files Changed
AllowInsecureUnlockguard toSign()andSignTypedData(), making them consistent with the existing guard inSendTransaction(). The guard is correctly placed before any keyring access, and the error message matches the existing pattern. Only a minor style note:fmt.Errorfwithout format verbs could beerrors.New.SignandSignTypedDataverifying rejection whenAllowInsecureUnlock=false. Tests are correctly placed as the first case in each suite so they run with a freshSetupTest()reset (which setsAllowInsecureUnlock=true) before being overridden byregisterMock().Sequence Diagram
sequenceDiagram participant Client as JSON-RPC Client participant Backend as Backend Note over Backend: AllowInsecureUnlock guard (NEW in Sign & SignTypedData) Client->>Backend: eth_sign / eth_signTypedData alt AllowInsecureUnlock = false Backend-->>Client: error: "account unlock with HTTP access is forbidden" else AllowInsecureUnlock = true Backend->>Backend: Keyring.KeyByAddress(from) alt key not found Backend-->>Client: error: ErrNoMatch else key found Backend->>Backend: Keyring.SignByAddress(from, data) Backend-->>Client: signature (hexutil.Bytes) end end Client->>Backend: eth_sendTransaction alt AllowInsecureUnlock = false Backend-->>Client: error: "account unlock with HTTP access is forbidden" else AllowInsecureUnlock = true Backend->>Backend: sign + broadcast tx Backend-->>Client: txHash endPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix: add AllowInsecureUnlock guard to et..." | Re-trigger Greptile
Summary by CodeRabbit
Bug Fixes
Tests