Skip to content

fix: close TOCTOU in LoadLocalSigner and LoadEVMSigner (PILOT-86)#3

Open
matthew-pilot wants to merge 1 commit into
mainfrom
openclaw/pilot-86-20260528-062900
Open

fix: close TOCTOU in LoadLocalSigner and LoadEVMSigner (PILOT-86)#3
matthew-pilot wants to merge 1 commit into
mainfrom
openclaw/pilot-86-20260528-062900

Conversation

@matthew-pilot
Copy link
Copy Markdown
Collaborator

What

Closes a time-of-check/time-of-use (TOCTOU) race in two identity-loading functions:

  • pkg/wallet/signer.go LoadLocalSigner (Ed25519 key)
  • pkg/evm/key.go LoadEVMSigner (secp256k1 key)

Both used os.Stat(path) to validate 0600 permissions, then os.ReadFile(path) to load the key material. An attacker with local filesystem access could chmod 0644 between the two syscalls, defeating the permission check entirely.

Fix

Replace the two-step path-based check with a single fd-based operation:

// Before (TOCTOU — attacker can chmod between these):
info, _ := os.Stat(path)
// ...check info.Mode()...
data, _ := os.ReadFile(path)

// After (atomic — all ops on same inode handle):
fd, _ := os.Open(path)
info, _ := fd.Stat()
// ...check info.Mode()...
data, _ := io.ReadAll(fd)

All three operations (open, stat, read) now target the same inode via the file descriptor — the kernel guarantees identity of the underlying file.

Verification

go build ./...  — clean
go vet ./...   — clean
go test ./...  — 5/5 packages pass

Jira

PILOT-86 — Wallet TOCTOU on private-key file permission check

Replace os.Stat + os.ReadFile with os.Open + fd.Stat + io.ReadAll to
eliminate the time-of-check/time-of-use window where an attacker can
chmod the identity file between the permission check and the read.

pkg/wallet/signer.go LoadLocalSigner: os.Stat→fd.Stat on opened fd
pkg/evm/key.go LoadEVMSigner: same pattern
All three operations (stat, validate, read) now target the same
inode handle — the fd guarantees identity of the checked file.

Tests: 5/5 packages pass (go test ./...)
Vet: clean
@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 80.00000% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/evm/key.go 80.00% 1 Missing and 1 partial ⚠️
pkg/wallet/signer.go 80.00% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant