Conversation
libwallet PR #1 Security ReviewSummary
CRITICAL Issues1. Missing Required Functions and TypesSeverity: CRITICAL Issue: The file references Current: References undefined symbols throughout the file
Why: This code will not compile. The gomobile package needs its own implementations separate from the cgo package. 2. Password Security ViolationSeverity: CRITICAL Issue: Password passed as Current: func SignMessage(name, message, address, password string) (string, error) {
// ...
if err := w.MainWallet().Unlock(w.ctx, []byte(password), nil); err != nil {Suggested: func SignMessage(name, message, address string, password []byte) (string, error) {
defer func() {
for i := range password {
password[i] = 0
}
}()
if err := w.MainWallet().Unlock(w.ctx, password, nil); err != nil {Why: Strings cannot be zeroed from memory in Go. Passwords MUST be passed as Note: Gomobile API restriction - If gomobile cannot accept 3. Extended Key Type SafetySeverity: CRITICAL Issue: Gomobile doesn't properly support uint8/uint16/uint64. Using type conversions that may cause issues. Current: func CreateExtendedKey(createExtKeyJSON string) (string, error) {
// ...
extKey, err := dcr.CreateExtendedKey(
createExt.Key,
createExt.ParentKey,
createExt.ChainCode,
createExt.Network,
uint8(createExt.Depth), // Unsafe conversion
uint32(createExt.ChildN), // Unsafe conversion
createExt.IsPrivate,
)Suggested: Define type CreateExtendedKeyReq struct {
Key string `json:"key"`
ParentKey string `json:"parentkey"`
ChainCode string `json:"chaincode"`
Network string `json:"network"`
Depth int `json:"depth"` // Changed from uint8
ChildN int `json:"childn"` // Changed from uint32
IsPrivate bool `json:"isprivate"`
}
// Add validation:
if createExt.Depth < 0 || createExt.Depth > 255 {
return "", fmt.Errorf("depth must be 0-255, got %d", createExt.Depth)
}
if createExt.ChildN < 0 {
return "", fmt.Errorf("childN must be non-negative, got %d", createExt.ChildN)
}Why: Gomobile has known issues with uint8/uint16/uint64 types. Use HIGH Priority4. No Mutex Protection for loadedWalletSeverity: HIGH Issue: Missing mutex protection when accessing shared wallet map. Required: The var (
wallets = make(map[string]*wallet)
walletsMtx sync.Mutex
)
func loadedWallet(name string) (*wallet, bool) {
walletsMtx.Lock()
defer walletsMtx.Unlock()
w, ok := wallets[name]
return w, ok
}Why: Concurrent access to the wallets map without synchronization causes race conditions and potential crashes. Reference: cgo/utils.go:8-18 MEDIUM Priority5. Generic Error Wrapping MissingSeverity: MEDIUM Issue: Errors not wrapped with Current: Why: Using Locations: Lines 35, 56, 60, 86, 92, 118, 147, 162, 176, 189, 193, 201, 205, 225 SUGGESTIONS6. Inconsistent Error MessagesSeverity: SUGGESTION Issue: Inconsistent error messages - "does not exist" vs "is not loaded" Current: // Line 23
return "", fmt.Errorf("wallet with name %q is not loaded", name)
// Line 185
return "", fmt.Errorf("wallet with name %q does not exist", name)Suggested: Use consistent terminology. Recommend "is not loaded" throughout. Why: Consistency improves debugging and user experience. 7. Password Error Handling Could Be More GenericSeverity: SUGGESTION Issue: Wallet unlock errors may leak information about password validity. Current: if err := w.MainWallet().Unlock(w.ctx, []byte(password), nil); err != nil {
return "", fmt.Errorf("cannot unlock wallet: %v", err)
}Suggested: Consider using a generic error: if err := w.MainWallet().Unlock(w.ctx, password, nil); err != nil {
return "", ErrInvalidPassphrase
}Why: According to security guidelines, crypto errors should be generic to avoid leaking details. However, this may be acceptable for user-facing API where detailed feedback is needed. Consider the threat model. Security Checklist Results
Action ItemsBefore this PR can merge:
Additional NotesThis PR appears to be creating gomobile bindings by adapting the cgo implementation. Good approach! However, several critical pieces are missing that exist in the cgo version. Recommend:
Compare with the reference implementation in |
|
[CRITICAL] gomobile/addresses.go:21 - Missing This function is undefined and needs to be implemented with proper mutex protection. See cgo/utils.go:8-18 for reference. |
|
[CRITICAL] gomobile/addresses.go:67 - Password Security Violation Password parameter is Suggested fix: func SignMessage(name, message, address string, password []byte) (string, error) {
defer func() {
for i := range password {
password[i] = 0
}
}()
if err := w.MainWallet().Unlock(w.ctx, password, nil); err != nil {If gomobile cannot accept |
|
[CRITICAL] gomobile/addresses.go:150 - Missing Required type definition: type AddressesRes struct {
Used []string `json:"used"`
Unused []string `json:"unused"`
Index uint32 `json:"index"`
}Note: Consider using |
|
[CRITICAL] gomobile/addresses.go:220-221 - Gomobile Type Incompatibility Gomobile doesn't properly support uint8/uint16/uint64 types. Using conversions like Suggested fix - Use type CreateExtendedKeyReq struct {
Key string `json:"key"`
ParentKey string `json:"parentkey"`
ChainCode string `json:"chaincode"`
Network string `json:"network"`
Depth int `json:"depth"` // Use int, not uint8
ChildN int `json:"childn"` // Use int, not uint32
IsPrivate bool `json:"isprivate"`
}
// Add range validation
if createExt.Depth < 0 || createExt.Depth > 255 {
return "", fmt.Errorf("depth must be 0-255, got %d", createExt.Depth)
}
if createExt.ChildN < 0 {
return "", fmt.Errorf("childN must be non-negative, got %d", createExt.ChildN)
} |
|
[CRITICAL] gomobile/addresses.go:199-203 - Missing These types need to be defined. Suggested: type AddrFromExtKey struct {
Key string `json:"key"`
Path string `json:"path"`
AddrType string `json:"addrtype"`
UseChildBIP32Std bool `json:"usechildbip32std"`
}
type CreateExtendedKeyReq struct {
Key string `json:"key"`
ParentKey string `json:"parentkey"`
ChainCode string `json:"chaincode"`
Network string `json:"network"`
Depth int `json:"depth"` // Use int for gomobile
ChildN int `json:"childn"` // Use int for gomobile
IsPrivate bool `json:"isprivate"`
}Recommend creating |
|
[CRITICAL] gomobile/addresses.go:29, 50, 174 - Missing These constants are referenced but not defined: const (
ErrCodeNotSynced = 1
)
const defaultAccount = "default"Recommend creating these in |
|
[HIGH] Multiple locations - Missing error wrapping with %w Errors should be wrapped with Current: Affected lines: 35, 56, 60, 86, 92, 118, 147, 162, 176, 189, 193, 201, 205, 225 |
Review Complete ✅I've completed a comprehensive security review of this PR following the libwallet security guidelines. Summary
Most Critical Issues to Address First:
Next Steps:
The detailed review with specific line numbers and code suggestions is in the comments above. Feel free to ask if you need clarification on any of the issues! |
add mobile