Skip to content

Commit 71ed5e5

Browse files
fix(security): auth for bounty claim, SSL verification, remove hardcoded admin key (#2800)
1. beacon_api.py: Add X-Admin-Key authentication to /api/bounties/<id>/claim - Previously anyone could claim bounties without authentication - Now requires RC_ADMIN_KEY via X-Admin-Key header (same as complete_bounty) 2. beacon_api.py: Enable SSL verification in sync_bounties - Previously disabled SSL verification unconditionally - Now verifies by default; opt-out via RC_DISABLE_SSL_VERIFY=1 env var 3. fleet_immune_system.py: Remove hardcoded admin key fallback - Previously fell back to 'rustchain_admin_key_2025_secure64' when RC_ADMIN_KEY env var was not set - Now requires RC_ADMIN_KEY to be set; endpoints return 503 if missing - Also uses hmac.compare_digest for timing-safe comparison RTC: RTC4642c5ee8467f61ed91b5775b0eeba984dd776ba Co-authored-by: haoyousun60-create <cdsun88@users.noreply.github.com>
1 parent 69396d8 commit 71ed5e5

2 files changed

Lines changed: 28 additions & 10 deletions

File tree

node/beacon_api.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Provides endpoints for agents, contracts, bounties, reputation, and chat.
55
"""
66
import json
7+
import os
78
import time
89
import hashlib
910
import sqlite3
@@ -536,10 +537,13 @@ def sync_bounties():
536537

537538
all_bounties = []
538539

539-
# Create SSL context that doesn't verify (for demo)
540+
# SSL verification: enabled by default, set RC_DISABLE_SSL_VERIFY=1 to skip
540541
ctx = ssl.create_default_context()
541-
ctx.check_hostname = False
542-
ctx.verify_mode = ssl.CERT_NONE
542+
if os.environ.get('RC_DISABLE_SSL_VERIFY', '0') == '1':
543+
import logging
544+
logging.warning('[beacon_api] SSL verification disabled via RC_DISABLE_SSL_VERIFY — not recommended for production')
545+
ctx.check_hostname = False
546+
ctx.verify_mode = ssl.CERT_NONE
543547

544548
for repo in repos:
545549
try:
@@ -625,8 +629,16 @@ def sync_bounties():
625629

626630
@beacon_api.route('/api/bounties/<bounty_id>/claim', methods=['POST'])
627631
def claim_bounty(bounty_id):
628-
"""Claim a bounty for an agent."""
632+
"""Claim a bounty for an agent (admin-only)."""
629633
try:
634+
import os, hmac
635+
admin_key = os.environ.get("RC_ADMIN_KEY", "")
636+
if not admin_key:
637+
return jsonify({'error': 'RC_ADMIN_KEY not configured — endpoint disabled'}), 503
638+
provided_key = request.headers.get("X-Admin-Key", "")
639+
if not hmac.compare_digest(provided_key, admin_key):
640+
return jsonify({'error': 'Unauthorized — admin key required to claim bounties'}), 401
641+
630642
data = request.get_json()
631643
agent_id = data.get('agent_id')
632644

rips/python/rustchain/fleet_immune_system.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -991,9 +991,12 @@ def register_fleet_endpoints(app, DB_PATH):
991991

992992
@app.route('/admin/fleet/report', methods=['GET'])
993993
def fleet_report():
994-
admin_key = request.headers.get("X-Admin-Key", "")
995-
import os
996-
if admin_key != os.environ.get("RC_ADMIN_KEY", "rustchain_admin_key_2025_secure64"):
994+
import os, hmac
995+
admin_key = os.environ.get("RC_ADMIN_KEY", "")
996+
if not admin_key:
997+
return jsonify({"error": "RC_ADMIN_KEY not configured — endpoint disabled"}), 503
998+
provided_key = request.headers.get("X-Admin-Key", "")
999+
if not hmac.compare_digest(provided_key, admin_key):
9971000
return jsonify({"error": "Unauthorized"}), 401
9981001

9991002
epoch = request.args.get('epoch', type=int)
@@ -1007,9 +1010,12 @@ def fleet_report():
10071010

10081011
@app.route('/admin/fleet/scores', methods=['GET'])
10091012
def fleet_scores():
1010-
admin_key = request.headers.get("X-Admin-Key", "")
1011-
import os
1012-
if admin_key != os.environ.get("RC_ADMIN_KEY", "rustchain_admin_key_2025_secure64"):
1013+
import os, hmac
1014+
admin_key = os.environ.get("RC_ADMIN_KEY", "")
1015+
if not admin_key:
1016+
return jsonify({"error": "RC_ADMIN_KEY not configured — endpoint disabled"}), 503
1017+
provided_key = request.headers.get("X-Admin-Key", "")
1018+
if not hmac.compare_digest(provided_key, admin_key):
10131019
return jsonify({"error": "Unauthorized"}), 401
10141020

10151021
miner = request.args.get('miner')

0 commit comments

Comments
 (0)