Skip to content

security: harden gRPC server — disable by default, bind to localhost#2078

Open
harshinsecurity wants to merge 1 commit into0xPolygon:developfrom
harshinsecurity:fix/grpc-security-hardening
Open

security: harden gRPC server — disable by default, bind to localhost#2078
harshinsecurity wants to merge 1 commit into0xPolygon:developfrom
harshinsecurity:fix/grpc-security-hardening

Conversation

@harshinsecurity
Copy link

Summary

The gRPC server in Bor currently starts unconditionally on all network interfaces (0.0.0.0:3131) with:

  • No authentication or authorization
  • No TLS encryption
  • No CLI flag to disable it
  • Server reflection enabled (allows service/method discovery)

This is inconsistent with HTTP-RPC and WS-RPC, which are disabled by default and bind to localhost. Any node with port 3131 reachable from the network exposes sensitive RPCs without credentials.

Impact

An unauthenticated attacker with network access to port 3131 can:

gRPC Method Impact
ChainSetHead(number) Force chain reorg to arbitrary block — causes the node to re-sync and lose recent state
PeersAdd(enode) / PeersRemove(enode) Manipulate the peer table — prerequisite for eclipse attacks
PeersList / PeersStatus Enumerate all connected peers, their enodes, and network topology
StatusBorStatus Leak sync state, current/highest block, network ID — reconnaissance
DebugPprof Extract CPU/memory/goroutine profiles — leak internal state

The most significant risk is Denial of Service: repeatedly calling ChainSetHead(0) forces the node to re-sync from genesis, effectively taking it offline. While this cannot steal funds or halt the Polygon network (requires multiple validators), it can degrade individual node availability.

CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H → 8.6 High

Changes

File Change
internal/cli/server/config.go Add Enabled bool field to GRPCConfig; default to false; change bind address from :3131 to 127.0.0.1:3131
internal/cli/server/server.go Guard gRPC startup with config.GRPC.Enabled check; fix GetGrpcAddr() to use net.SplitHostPort instead of brittle [1:] string slice
internal/cli/server/flags.go Add --grpc.enabled CLI boolean flag
internal/cli/server/helper.go Set config.GRPC.Enabled = true in test mock so existing tests pass
docs/cli/server.md Document new --grpc.enabled flag and updated default address

Behavior Change

Before After
gRPC server Always starts Only starts with --grpc.enabled
Default bind 0.0.0.0:3131 (all interfaces) 127.0.0.1:3131 (localhost only)
Opt-in flag None --grpc.enabled

This is a breaking change for anyone relying on the gRPC server being on by default. Operators who need gRPC must now explicitly pass --grpc.enabled. This is the same pattern used by --http and --ws and is the secure default.

How to Test

# Default: gRPC should NOT start
./build/bin/bor server --datadir /tmp/bor-test
# Verify port 3131 is NOT listening

# Explicit enable: gRPC starts on localhost
./build/bin/bor server --datadir /tmp/bor-test --grpc.enabled
# Verify port 3131 IS listening on 127.0.0.1 only

# Existing tests pass
go test ./internal/cli/server/...

For questions or discussion, feel free to reach out: hi@harshinsecurity.in

- Add 'Enabled' field to GRPCConfig (default: false), requiring
  explicit --grpc.enabled flag to start the gRPC server
- Change default bind address from 0.0.0.0:3131 to 127.0.0.1:3131
- Guard gRPC server startup with Enabled check in NewServer()
- Add --grpc.enabled CLI flag in flags.go
- Fix GetGrpcAddr() to use net.SplitHostPort instead of string slice
- Update docs and test helper for compatibility

The gRPC server currently starts unconditionally on all interfaces
(0.0.0.0:3131) with no authentication, no TLS, and no way to disable
it. This is inconsistent with HTTP-RPC and WS-RPC which are disabled
by default. An attacker with network access can invoke sensitive RPCs
including ChainSetHead (reorg), PeersAdd/Remove (eclipse attacks),
and StatusBorStatus (reconnaissance) without credentials.
@sonarqubecloud
Copy link

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