Skip to content

fix(security): prevent cluster heartbeat address hijack without mTLS - #166

Merged
AlexanderWagnerDev merged 2 commits into
mainfrom
cursor/application-security-review-a540
Aug 15, 2026
Merged

fix(security): prevent cluster heartbeat address hijack without mTLS#166
AlexanderWagnerDev merged 2 commits into
mainfrom
cursor/application-security-review-a540

Conversation

@cursor

@cursor cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Security review fix

Closes #165

Finding: Cluster heartbeat member address hijack (High)

  • Location: src/cluster/manager.rs
  • Impact: On plaintext clusters (CLUSTER_TLS_ENABLED=false), any holder of the shared CLUSTER_SECRET can authenticate as an existing member node_id and send Heartbeat frames with attacker-controlled control_addr / media_addr. Receiving nodes overwrite peer routing metadata and open outbound media mesh connections to the attacker, enabling interception/injection of inter-node control and RTMP relay traffic.
  • Remediation: Only apply heartbeat-supplied routing addresses when cluster mTLS is enabled (certificate binds the connection to node_id). Plaintext clusters keep addresses from JoinRequest (with admin_proof) and topology refresh only.

Changes

  • Add heartbeat_routing_addrs() helper to gate address updates on tls_enabled.
  • Skip meta.set_addrs, network.upsert_node, and hub.connect_peer from heartbeat when mTLS is off.
  • Unit tests for plaintext vs mTLS behavior.

Operational note: Production cluster deployments should still enable mTLS and restrict CLUSTER_BIND / CLUSTER_MEDIA_BIND to a private network.

Open in Web View Automation 

Note

Medium Risk
Security-critical cluster routing change with targeted tests; behavior change for plaintext deployments that relied on heartbeat-driven address updates.

Overview
Fixes a high-severity issue on plaintext clusters (CLUSTER_TLS_ENABLED=false): any peer with CLUSTER_SECRET could heartbeat as another node_id and push fake control_addr / media_addr, causing nodes to retarget control routing and open media mesh connections to an attacker.

Introduces heartbeat_routing_addrs() so heartbeat payloads only update routing when mTLS is on (identity is certificate-bound). On plaintext, health still uses addresses resolved from already registered metadata (join / topology), not peer-reported values. meta.set_addrs, network.upsert_node, and connect_peer from heartbeats run only when TLS is enabled.

Adds unit tests for plaintext (ignore reported addrs) vs mTLS (accept reported addrs). Cargo.lock bumps several transitive crate versions.

Reviewed by Cursor Bugbot for commit 7e61db4. Bugbot is set up for automated code reviews on this repo. Configure here.

cursoragent and others added 2 commits August 15, 2026 02:06
On plaintext clusters the shared CLUSTER_SECRET lets any holder
authenticate as an existing member node_id. Heartbeat payloads used to
overwrite peer control/media addresses and trigger outbound mesh
connections to attacker infrastructure.

Only apply heartbeat-supplied routing addresses when cluster mTLS is
enabled (certificate binds the connection to node_id). Plaintext
clusters keep addresses from join/topology refresh only.

Co-authored-by: Alexander Wagner <info@alexanderwagnerdev.com>
@AlexanderWagnerDev
AlexanderWagnerDev marked this pull request as ready for review August 15, 2026 17:34
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@AlexanderWagnerDev
AlexanderWagnerDev merged commit e9a6aca into main Aug 15, 2026
15 checks passed
@AlexanderWagnerDev
AlexanderWagnerDev deleted the cursor/application-security-review-a540 branch August 15, 2026 17:35

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7e61db4. Configure here.

Comment thread src/cluster/manager.rs
tokio::spawn(async move {
let _ = hub.connect_peer(mid, &m).await;
});
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followers never learn new member addresses

High Severity

On plaintext clusters, heartbeat handling no longer writes meta, network.nodes, or media peers, and nothing else seeds those caches when membership grows. Existing followers therefore never learn a new joiner’s control or media addresses: they stop sending heartbeats to that node (so the joiner can mark them DOWN), skip subscribe_remote when it owns a stream, and omit it from standby placement. Join and topology refresh only cover the leader, the joiner, and process restart—not a running third member. Default tls_enabled is off, so this hits typical multi-node deployments.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7e61db4. Configure here.

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.

Cluster heartbeat allows member address hijack with CLUSTER_SECRET only (no mTLS)

2 participants