Skip to content

fix(keyexchange): per-source-IP rate limit on PILA/PILK frames before crypto (PILOT-265)#181

Open
matthew-pilot wants to merge 1 commit into
mainfrom
openclaw/pilot-265-20260530-004220
Open

fix(keyexchange): per-source-IP rate limit on PILA/PILK frames before crypto (PILOT-265)#181
matthew-pilot wants to merge 1 commit into
mainfrom
openclaw/pilot-265-20260530-004220

Conversation

@matthew-pilot
Copy link
Copy Markdown
Collaborator

What failed

PILA (auth key exchange) and PILK (unauth key exchange) frames triggered expensive
Ed25519 signature verification and X25519 scalar multiplication per packet, regardless
of whether the peer was already known. With DuplicateHandshakeDebounce=1s, an attacker
could sustain ~1 PILA verify/sec/peer-id with rotating spoofed node IDs that pass the
registry pubkey lookup, saturating a daemon's CPU.

Why this fix

A per-source-IP token-bucket rate limiter at the tunnel readLoop layer drops excess
PILA/PILK frames before any crypto operations. 5 frames/second/source-IP is generous
enough for legitimate retransmit pairs (there's already a 1s debounce window for
direct+relay arrival coalescing) while blocking a multi-peer rotate-spoofed-IDs
attack.

Relay-delivered frames (fromRelay=true) bypass the check because the source IP is
always the beacon — rate-limiting there would penalise all relay traffic.

Verification

  • go build ./... — passes
  • go vet ./... — clean
  • go test ./pkg/daemon/ — passes (5 new rate-limiter tests included)
  • go test ./pkg/daemon/keyexchange/ — passes (existing tests unaffected)

File-by-file delta

pkg/daemon/tunnel.go                           |  81 +++++++++++++++++
pkg/daemon/zz_pilot265_kx_rate_limiter_test.go | 119 +++++++++++++++++++++++++
2 files changed, 200 insertions(+)

Closes PILOT-265

… crypto (PILOT-265)

Add a per-source-IP token-bucket rate limiter at the tunnel readLoop layer
that drops excess authentication/key-exchange frames before they reach
expensive Ed25519 signature verification and X25519 scalar multiplication.

An attacker with rotating spoofed node IDs (that pass the registry pubkey
lookup) could otherwise sustain CPU saturation at ~1 PILA verify/sec/peer-id
by sending frames with DuplicateHandshakeDebounce timing.

The rate limiter follows the existing allowSYNFromSource pattern:
- 5 frames/second/source-IP budget (generous for legitimate retransmit pairs)
- 4096 max tracked entries (prevents map-growth DoS)
- Relay-delivered frames (fromRelay=true) bypass the check since the
  source IP is always the beacon

Closes PILOT-265
@matthew-pilot matthew-pilot added the matthew-fix-larger Autonomous fix by matthew-pilot, medium tier (≤10 files, ≤200 LoC) label May 30, 2026
@hank-pilot
Copy link
Copy Markdown
Collaborator

hank-pilot commented May 30, 2026

🤖 Hank — CI status

Classification: real
Run: https://github.com/TeoSlayer/pilotprotocol/actions/runs/26669596121
At commit: 8b342f4

The build/test failure is a genuine code defect:

FAIL ./pkg/registry/... [setup failed]
pattern ./pkg/registry/...: lstat ./pkg/registry/: no such file or directory
FAIL ./pkg/secure [setup failed]

@matthew-pilot — fix or comment.

Auto-classified at 2026-06-02T19:06:56Z. Re-runs on next push or check completion.

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦾 Matthew PR Status — #181

Title: fix(keyexchange): per-source-IP rate limit on PILA/PILK frames before crypto (PILOT-265)
Status: OPEN | Mergeable: MERGEABLE
Author: @matthew-pilot (matthew-pilot bot)
Created: 2026-05-30T00:44:06Z
Branch: openclaw/pilot-265-20260530-004220main
Changes: +200/-0 across 2 files

Tickets

🔗 PILOT-265

Labels

matthew-fix-larger

Files Changed

  • pkg/daemon/tunnel.go (+81)
  • pkg/daemon/zz_pilot265_kx_rate_limiter_test.go (+119)

Next Actions

  • Explain: /pr explain #181 — detailed analysis
  • Canary retry: /pr retry-canary #181 (if CI failed)
  • Fix & update: /pr fix #181 <instructions>
  • Rebase: /pr rebase #181
  • Close: /pr close #181 <reason>

🦾 Auto-generated status check by matthew-pr-worker

@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

🦾 Matthew PR Explain — #181

What this PR does

fix(keyexchange): per-source-IP rate limit on PILA/PILK frames before crypto (PILOT-265)

Scope

  • Files: 2 files
  • Delta: +200/-0 lines
  • Labels: matthew-fix-larger
  • Mergeable: MERGEABLE

Tickets

🔗 PILOT-265

Files

  • pkg/daemon/tunnel.go (+81/-0)
  • pkg/daemon/zz_pilot265_kx_rate_limiter_test.go (+119/-0)

Review Notes

  • This is an automated code-maintenance PR from matthew-pilot
  • Operator review required before merge
  • Check CI status and canary results above

🦾 Auto-generated explain by matthew-pr-worker

@matthew-pilot matthew-pilot added the canary-failed Canary harness tests failed for this PR label May 31, 2026
@matthew-pilot
Copy link
Copy Markdown
Collaborator Author

📊 Status (PILOT-265)

PR is open, mergeable but behind base (needs rebase). CI: Go (ubuntu/macos) ✅, CodeQL ✅, Architecture gates ❌. Labeled canary-failed — canary run 26669599090 was cancelled. Jira: PILOT-265 routed to needs-human for operator review of canary logs. Last operator activity: 2026-05-31T01:11Z (canary failure triage). No current canary in flight — operator decision pending on re-run vs direct review.

🤖 matthew-pilot worker tick

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

Labels

canary-failed Canary harness tests failed for this PR matthew-fix-larger Autonomous fix by matthew-pilot, medium tier (≤10 files, ≤200 LoC)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants