Skip to main content

Penetration Test Results

Tested against live production node (Foundation node) on 2026-04-15. 6 test suites, all non-destructive.

Node started at height ~140,282. After all tests: height 140,811. Chain never stalled, never crashed, kept producing blocks throughout.


Test 1: RPC Flood

Threw 1,000 GET requests at /chain/info as fast as curl could fire them.

  • 294 succeeded (HTTP 200)
  • 706 rate-limited (HTTP 429)
  • Rate limiting kicked in after ~60 requests/minute as expected
  • Node stayed responsive the entire time
  • Had to wait 60s for rate limit cooldown before the next test

Verdict: PASS.


Test 2: Malformed Requests

32 edge cases: invalid JSON, missing fields, wrong types, SQL injection, XSS, path traversal, null bytes, boundary values, malformed transactions.

  • 31 passed — node returned proper HTTP error codes
  • 1 "fail" — SQL injection in URL path ('; DROP TABLE;--) got connection reset. Nginx rejecting the special characters before reaching the node
  • All RPC endpoints returned 401 (API key required) — correct production behavior
  • XSS in address path: HTTP 400. Path traversal: HTTP 404. Huge block index: HTTP 404. All handled.

Verdict: PASS. No panics, no crashes.


Test 3: Double Spend

Two transactions with the same nonce from the same fake address — one to victim A, one to victim B. Attempted via both REST and JSON-RPC.

  • Both REST submissions: HTTP 401 (auth required)
  • Both RPC submissions: blocked by auth

The API key layer blocks unauthenticated tx submissions before they reach validation. Double-spend protection (nonce validation, txid dedup) sits behind auth.

Verdict: PASS.


Test 4: Transaction Spam

100 transactions rapid-fire, then 5 duplicate-nonce transactions.

  • 100/100 rejected (401 auth + validation)
  • 0 accepted, 0 server errors
  • Dup nonce: first got 401, rest got 429 (rate limited)

Verdict: PASS. Zero errors.


Test 5: P2P Connection Flood

120 simultaneous TCP connections to port 30303, held for 5 seconds.

  • 120/120 connections opened
  • API checked 5 times during flood: all HTTP 200, latency 60-80ms
  • Zero impact on block production or API responsiveness

Verdict: PASS.


Test 6: Oversized Payloads

Progressive sizes (1KB to 2MB) on RPC and TX endpoints, plus batch size tests.

  • 1KB, 10KB: accepted (processed to auth check)
  • 100KB-900KB: connection reset — nginx drops large payloads before they reach the node (stricter than node's 1 MiB limit)
  • 1MB+: rejected
  • Batch 10-200: all hit auth check (401). Can't verify batch cap without valid API key from outside

Verdict: PASS. Nginx acts as extra defense layer.


Summary

TestResult
RPC Flood (1000 req)PASS
Malformed (32 cases)PASS (31/32)
Double SpendPASS
TX Spam (105 txs)PASS
P2P Flood (120 conn)PASS
Oversized (16 cases)PASS

Node: height 140,282 → 140,811 during testing. Never missed a beat.

Observations

  1. Rate limiting is aggressive — 60 req/min per IP. Need ~60s cooldown between burst tests.
  2. Nginx drops payloads >~50KB before they hit the node — stricter than the node's own 1 MiB limit. Attackers hit nginx first.
  3. API key auth blocks all write ops from unauthenticated sources. Validation logic never runs for unauthenticated requests.
  4. P2P and API are independent. Flooding port 30303 has zero effect on port 8545.

Running the Scripts

./pentest/run_all.sh # local node
./pentest/run_all.sh [NODE_IP]:8545 # specific node
./pentest/test4_malformed.sh localhost:8545 # individual test

Note: scripts need nc (netcat) and bc which aren't available on Windows Git Bash. Python can substitute for the TCP tests.