74653 bc insight base consensus exposes admin rpc despite rpc enable admin being disabled enabling hidden unsafe branch partition via admin postunsafepayload
Submitted on Apr 24th 2026 at 03:04:10 UTC by @cgdusek for Audit Comp | Base Azul
Report ID: #74653
Report Type: Blockchain/DLT
Report severity: Insight
Target: https://github.com/base/base/releases/tag/v0.8.0-rc.15
Impacts:
Unintended chain split (network partition)
Description
Vulnerability Report
Selected fields:
program:
Base Azulasset:
Offchain Componentsimpact:
High: Unintended chain split (network partition)title:
base-consensus exposes admin RPC despite --rpc.enable-admin being disabled, enabling hidden unsafe-branch partition via admin_postUnsafePayload
Executive summary of issue
base-consensus parses --rpc.enable-admin / BASE_NODE_RPC_ENABLE_ADMIN, but the normal node RPC actor does not enforce that flag before merging the admin_* namespace. A caller who can reach the normal sequencer RPC socket can therefore use admin_postUnsafePayload even when the operator did not enable admin RPC. The combined PoC proves the end-to-end consequence on the pinned release: a hidden valid unsafe payload can be injected onto a poisoned subset, the active sequencer then builds descendants on that hidden branch, a second poisoned peer follows it, and a clean validator remains on the public head because it never observed the hidden parent. That is a proved unintended unsafe-head network partition.
Classification and scope justification
Exact program criteria match
asset name(s) exactly as listed on scope page:
Offchain Componentsspecific scoped asset(s) supporting this severity claim: Base-native
base-consensusoffchain code inbase/baseundercrates/client,crates/consensus/rpc,crates/consensus/service,crates/consensus/engine, andcrates/consensus/gossipexact current Immunefi scope picker URL(s) supporting this severity claim: the live scope page did not expose separate per-asset picker URLs; use Base Azul scope
online form asset picker selection:
Offchain Componentsexact current Immunefi scope picker URL for selected form asset: the live scope page does not expose a separate per-asset picker URL; use the Base Azul scope page, checked 2026-04-23
selected severity from scope page:
Highselected impact title from scope page:
Unintended chain split (network partition)exact scope wording: the live scope lists
Offchain Componentsas an asset and says only Base-native code such as CL and EL components is in scope; it also listsactions,devnet,baseup, andetcas out of scope, so this report keeps the bug claim on Base-nativecrates/code onlyscope page last checked:
2026-04-23why this matches the demonstrated consequence: the combined PoC proves that the disabled-admin bypass exposes
admin_postUnsafePayload, that a valid hidden payload can be injected into a poisoned subset, that the active sequencer builds descendants on that hidden branch, and that a clean validator remains on a different branch because the hidden parent never reached it. That is the listed High network-partition lane.
Why higher or adjacent criteria do not fit
closest higher severity criterion considered:
Unintended permanent chain split requiring hard fork (network partition requiring hard fork)why the report does not satisfy it: the PoC proves unsafe-head divergence on a poisoned subset. It does not prove permanence, safe/finalized divergence, hard-fork necessity, or that manual restart/reconfiguration cannot restore convergence. The live program also says reports that assume a service will not be manually restarted with possibly different configurations may be downgraded.
closest adjacent same/lower criteria considered:
Temporary freezing of network transactions by delaying one block by 500% or more of the average block time of the preceding 24 hours beyond standard difficulty adjustmentswhy the selected criterion fits better: the selected proved consequence is not just a stalled sequencer. The combined artifact shows two validator views diverging onto different unsafe branches.
Feasibility boundary
proven effect: unauthorized access to the disabled admin namespace plus
admin_postUnsafePayloadcan create a local unsafe-head network partition between a poisoned subset and a clean validatorproven technical requirements inside the PoC: the attacker supplies a fully valid hidden payload extending the shared public head, injects it through the exposed admin route, and the active sequencer then builds descendants on that hidden branch
bounded-inference deployment precondition: the attacker can reach the normal sequencer RPC socket in deployment. This report does not claim a probed live public endpoint.
unsupported / not claimed escalation path: this packet does not claim permanent or finalized chain split, hard-fork-required partition, invalid L1 finalization, bridge loss, or direct theft
Out-of-scope exclusion check
relevant out-of-scope exclusions reviewed: the live scope excludes
actions,devnet,baseup, andetc; it excludes impacts requiring leaked keys, privileged addresses, mainnet or public testnet testing, phishing, and denial-of-service attacks executed against project assetsexcluded assumptions not used by this exploit: no leaked key, privileged address, governance action, TEE/ZK proof compromise, invalid state-root proof,
etcdeployment file, mainnet testing, public testnet testing, live endpoint probing, or attack traffic against project assets is requiredPoC harness boundary: the reviewer test is copied into
actions/harnessonly as local scaffolding inside a fresh pinned clone; the bug claim and the asserted runtime paths remain in in-scopecrates/code
Finding details
Public documentation invariant
Public evidence checked on 2026-04-23:
The live Base Azul scope page, checked 2026-04-23 lists
Offchain Componentsas an in-scope asset and identifies Base's migration tobase-reth-nodeandbase-consensusas a main Azul change.The official Base Azul upgrade guide, checked 2026-04-23 says most
base-consensusconfiguration is preconfigured inbase/node.env.mainnetand.env.sepolia, and it mapsOP_NODE_RPC_ENABLE_ADMINtoBASE_NODE_RPC_ENABLE_ADMIN.The stock
base/nodeSepolia template at commitca91ddb0683d6ebde184e96d3515863e80bfb918lines 24-95 preconfiguresbase-consensusRPC host/port settings but does not explicitly setBASE_NODE_RPC_ENABLE_ADMIN.The analogous OP Stack node guide, checked 2026-04-23 warns that the rollup-node RPC should not be exposed publicly because it could expose admin controls.
The release-pinned admin namespace includes operational methods such as
postUnsafePayload,startSequencer,stopSequencer,setRecoverMode,overrideLeader, andresetDerivationPipelineinAdminApilines 162-204.
The resulting invariant is inference-backed rather than stated in one sentence: the normal base-consensus RPC listener should expose the admin_* namespace only when the operator explicitly enables the admin API. This bug breaks that boundary because RpcActor::start merges AdminRpc whenever normal startup supplies network_admin, even when --rpc.enable-admin is unset. The current PoC then proves that this unauthorized admin surface is strong enough to create an unsafe-head network partition through admin_postUnsafePayload, not just to expose dormant admin methods in theory.
Root cause
RpcBuilder contains an enable_admin field, as shown in crates/consensus/rpc/src/config.rs lines 7-24, but the registration path ignores it. In crates/consensus/service/src/actors/rpc/actor.rs lines 101-123, RpcActor::start merges AdminRpc whenever network_admin is Some. It checks other optional modules later in the same function, but it never checks enable_admin before merging the admin namespace.
Normal node startup supplies that network_admin channel in crates/consensus/service/src/service/node.rs lines 534-555. The exposed admin_postUnsafePayload route forwards an unsigned BaseExecutionPayloadEnvelope that contains no signature field in lines 17-25 through AdminRpc::admin_post_unsafe_payload lines 70-80 into NetworkActor forwarding lines 203-207. The normal gossip path, by contrast, requires a signed NetworkPayloadEnvelope in lines 239-249 and validates the unsafe block signer in BlockHandler lines 218-229.
Strongest demonstrated exploit path
{% stepper %} {% step %}
Attacker reaches the RPC socket
The attacker reaches the normal sequencer node HTTP RPC socket. The release CLI defaults that RPC socket to 0.0.0.0:9545 in crates/client/cli/src/rpc.rs lines 24-32, but this report keeps live reachability as an exploit precondition rather than a proved public exposure. {% endstep %}
{% step %}
The disabled-admin namespace is exposed
The attacker uses the exposed disabled-admin namespace to invoke admin_postUnsafePayload on nodes that should not have admin RPC at all. The route is exposed because RpcActor::start merges AdminRpc without checking enable_admin. {% endstep %}
{% step %}
A hidden valid payload is injected
The attacker injects a fully valid hidden payload extending the shared public head into the target sequencer and one peer through the admin route. The PoC proves the method accepts that hidden payload and advances the poisoned subset to the hidden head. {% endstep %}
{% step %}
The sequencer builds descendants on the hidden head
The active sequencer then builds the next block from the hidden head. That behavior follows the current unsafe head in PayloadBuilder::build lines 56-63. {% endstep %}
{% step %}
The branches diverge
A second poisoned peer that observed the hidden ancestor follows the descendant, while a clean validator that only saw the public head rejects the descendant because the hidden parent was never observed. The combined PoC proves the poisoned subset and clean validator end on different branches. {% endstep %} {% endstepper %}
PoC-backed proof chain
{% stepper %} {% step %}
verify_admin_rpc_gate.py
verify_admin_rpc_gate.py proves that the release-pinned code parses --rpc.enable-admin but still exposes the admin namespace without checking that flag. {% endstep %}
{% step %}
admin_post_unsafe_payload_partition.rs
admin_post_unsafe_payload_partition.rs is injected into a fresh pinned clone and run through cargo test to prove the partition consequence. {% endstep %} {% endstepper %}
Observed high-signal markers from the combined artifact:
POC_MARKER_FLAG_PARSEDPOC_MARKER_ADMIN_MERGED_WITHOUT_ENABLE_ADMINPOC_MARKER_PUBLIC_HEAD_ESTABLISHEDPOC_MARKER_ADMIN_POST_UNSAFE_PAYLOAD_POISONS_SUBSETPOC_MARKER_POISONED_SEQUENCER_BUILDS_DESCENDANTPOC_MARKER_CLEAN_VALIDATOR_REJECTS_MISSING_PARENT_DESCENDANTPOC_MARKER_NETWORK_PARTITIONPOC_RESULT: PASS
The live secret gist ceb8c60b5af8e2e486d4299d8a4c0b5f was rechecked against the local mirror on 2026-04-23. The exact fresh AWS Spot rerun used gist revision cb6f5e8b0cb3f519e6b3ae0d211e00fd33453931 with the reviewer command bash run_poc.sh. The current live gist revision at the last congruence check is 37ba32dfeea10c18f12f8738a4834940efd1742e, which only narrows the README wording to the validated Ubuntu reviewer environment and leaves the runnable files unchanged.
PoC setup conditions
The PoC is local-only with respect to blockchain state. It clones the pinned base/base release, boots local harness actors, and never connects to Base mainnet, Base Sepolia, Ethereum, or any live RPC endpoint. On a stock root Ubuntu host, run_poc.sh bootstraps the Rust toolchain, Linux build packages, and Foundry when missing; on other environments, those requirements must be preinstalled as described in the gist README.
Exploit preconditions
The normal sequencer node's HTTP RPC socket is reachable by the attacker.
The node is running the affected
base-consensuscode path.The attacker can construct a fully valid payload on top of the current public unsafe head. The PoC proves this technically within the pinned local environment and does not require a privileged signer because the admin route bypasses the normal gossip signature gate.
No leaked key, privileged address, governance vote, TEE signer compromise, ZK soundness failure, invalid proof, public-network transaction, or public testnet/mainnet testing is required.
Deployment and in-scope surface
The bug-relevant surface is Base-native base-consensus code under crates/, which falls under the live Offchain Components asset. The PoC pins base/base commit de349fc9e8bf61531ce36ca57572345b03b2b097, tagged locally as v0.8.0-rc.15. This report does not claim that a specific public Base Sepolia RPC endpoint is internet-exposed; it claims the release-pinned scoped code exposes admin RPC on any normal sequencer RPC socket reachable by an attacker.
That reachability precondition is deployment-specific and is presented as a bounded inference rather than a proved live exposure. The release-pinned CLI defaults the base-consensus RPC to 0.0.0.0:9545 in crates/client/cli/src/rpc.rs lines 24-32. Base's official migration guide tells node operators to use the preconfigured base/node setup and start it with docker compose up on the Base Azul upgrade guide, checked 2026-04-23. The analogous OP Stack op-node guide explicitly warns that the rollup-node RPC should not be exposed publicly because it could expose admin controls on the OP node run guide, checked 2026-04-23.
Public-known / duplicate boundary
The public known-issues document linked from the live scope lists SP1, ZK service, Nitro/TEE, registrar, and proposer issues, but it does not describe this base-consensus admin RPC gate mismatch or an exposed-admin_postUnsafePayload partition path. Targeted GitHub issue/PR searches for admin_stopSequencer, admin_postUnsafePayload, BASE_NODE_RPC_ENABLE_ADMIN, AdminRpc::new, and enable_admin in base/base found no exact public issue or pull request describing this bug family.
Repository, file, and line of code where finding is found
Steps to replicate
All testing was performed locally only. I did not use mainnet or public testnet.
secret gist: PoC gist
recommended PoC name:
admin-rpc-enable-admin-bypass-network-partition
Expected high-signal output markers:
POC_MARKER_FLAG_PARSEDPOC_MARKER_ADMIN_MERGED_WITHOUT_ENABLE_ADMINPOC_MARKER_PUBLIC_HEAD_ESTABLISHEDPOC_MARKER_ADMIN_POST_UNSAFE_PAYLOAD_POISONS_SUBSETPOC_MARKER_POISONED_SEQUENCER_BUILDS_DESCENDANTPOC_MARKER_CLEAN_VALIDATOR_REJECTS_MISSING_PARENT_DESCENDANTPOC_MARKER_NETWORK_PARTITIONPOC_RESULT: PASS
Impact of finding
Short term
An attacker who can reach the normal sequencer RPC socket can use an admin method that should have been disabled to split validator views. The combined PoC proves a poisoned subset on one unsafe branch and a clean validator on another, which matches the live High network-partition lane.
Long term
The long-term consequence is continued integrity and availability risk while the vulnerable RPC surface remains reachable. This report does not claim permanent or finalized chain split, hard-fork-required partition, bridge loss, invalid state-root finalization on L1, or direct theft of funds.
Comparable public incidents
These are context only, not duplicates or direct proof of identical impact.
Security Advisory [Insecurely configured geth can make funds remotely accessible], August 29, 2015
Similar because remote reachability to an operator-gated RPC surface can convert node-local authority into attacker-controlled actions. Different because the impact there was fund access, not partition of validator views.
Security Alert - cpp-ethereum keeps accounts unlocked, May 31, 2016
Similar because exploitability depended on access to an exposed JSON-RPC surface that was not meant to grant blanket remote authority. Different because it was an account-unlock bug, not an admin namespace registration bug.
Mitigation suggestions
Gate
AdminRpc::new(...).into_rpc()inRpcActor::startonself.config.enable_admin.Add a focused RPC actor regression test proving that
admin_*methods are absent whenenable_admin=false, even whennetwork_adminis present.Add a regression test covering
admin_postUnsafePayloadspecifically so it cannot be reached through the normal RPC surface when admin mode is disabled.
Optional suggested patch
No untested code patch is included in this packet. The mitigation direction above is intentionally limited to the required gate and regression coverage.
References
Runnable PoC package
secret gist: PoC gist
recommended PoC name:
admin-rpc-enable-admin-bypass-network-partition
Live deployment / release confirmation
information: Base Azul information page, checked 2026-04-23
Relevant code paths
Scope / rules
PoC rules: Immunefi PoC guidelines
Public protocol documentation
Additional context / provenance
Submission notes
selected scope criterion:
High - Unintended chain split (network partition)specific scoped assets carrying the claim:
Offchain Components, specifically Base-nativebase-consensuscode undercrates/online form asset picker selection:
Offchain Componentsexact current Immunefi scope picker URL for selected form asset: the live scope page does not expose a separate per-asset picker URL; use the Base Azul scope page, checked 2026-04-23
severity anchor:
admin_postUnsafePayloadhidden-branch partition on a poisoned subsetbreadth-only variant:
admin_stopSequencerremains corroborating breadth from the same disabled-admin bug family, not the primary severity anchorexplicitly not claiming: permanent or finalized chain split, hard-fork-required partition, public endpoint exposure, Base mainnet impact, invalid state-root finalization on L1, TEE/ZK proof bypass, bridge loss, or direct theft
Link to Proof of Concept
https://gist.github.com/cgdusek/ceb8c60b5af8e2e486d4299d8a4c0b5f
Proof of Concept
PoC specification
Recommended PoC name:
admin-rpc-enable-admin-bypass-network-partition
Full PoC package:
One-sentence summary:
The PoC first proves that base-consensus exposes the admin_* namespace even when --rpc.enable-admin is disabled, then proves that admin_postUnsafePayload can seed a hidden valid unsafe branch that a poisoned subset follows while a clean validator remains on the public head.
Minimal file list:
README.mdOUTPUT.txtrun_poc.shverify_admin_rpc_gate.pyadmin_post_unsafe_payload_partition.rs
Run from a fresh clone or download of the gist:
Layout note:
GitHub gist stores all files at the gist root. Run the command from that root directory.
Expected high-signal output markers:
POC_MARKER_FLAG_PARSEDPOC_MARKER_ADMIN_MERGED_WITHOUT_ENABLE_ADMINPOC_MARKER_PUBLIC_HEAD_ESTABLISHEDPOC_MARKER_ADMIN_POST_UNSAFE_PAYLOAD_POISONS_SUBSETPOC_MARKER_POISONED_SEQUENCER_BUILDS_DESCENDANTPOC_MARKER_CLEAN_VALIDATOR_REJECTS_MISSING_PARENT_DESCENDANTPOC_MARKER_NETWORK_PARTITIONPOC_RESULT: PASS
Notes:
The PoC uses only local execution and pinned public dependencies. It does not connect to Base mainnet, Base Sepolia, Ethereum, or any live node RPC endpoint.
On a stock root Ubuntu host,
run_poc.shbootstraps the Rust toolchain, Linux build prerequisites, and Foundry when missing. Other environments should preinstall the requirements listed in the gist README.The full requirements and sample output live in the gist README and
OUTPUT.txt.
Was this helpful?