From 6b6b6fcc3b58a095cb47cb55945ceda6ba3de464 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Mon, 25 May 2026 13:46:11 +0000 Subject: [PATCH] Security fixes: SSL verification, SQL injection, auth bypass, hash_equals - Enable CURLOPT_SSL_VERIFYPEER on Groq and Claude API calls (MITM fix) - Parameterize agent_commands IN clause to prevent SQL injection - Add session/IP check for list/status/myip endpoints (auth bypass fix) - Use hash_equals() for registration key comparison (timing attack fix) --- api/endpoints/agent.php | 14 ++++++++++---- api/endpoints/chat.php | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/endpoints/agent.php b/api/endpoints/agent.php index cf90c42..5ffe940 100644 --- a/api/endpoints/agent.php +++ b/api/endpoints/agent.php @@ -51,7 +51,12 @@ $browserActions = ['list', 'status', 'myip']; if ($agentAction !== 'register') { if (in_array($agentAction, $browserActions)) { - $agent = null; // browser-accessible via session auth already validated by api.php + $token = $_SESSION['jarvis_token'] ?? ''; + $localIP = $_SERVER['REMOTE_ADDR'] ?? ''; + if (empty($token) && !in_array($localIP, ['127.0.0.1', '::1', JARVIS_IP])) { + agent_error(401, 'Unauthorized'); + } + $agent = null; } else { if (empty($agentKey)) agent_error(401, 'X-Agent-Key header required'); $agent = get_agent_by_key($agentKey); @@ -67,7 +72,7 @@ switch ($agentAction) { case 'register': if ($method !== 'POST') agent_error(405, 'POST only'); $regKey = $_SERVER['HTTP_X_REGISTRATION_KEY'] ?? ($data['registration_key'] ?? ''); - if ($regKey !== AGENT_REGISTRATION_KEY) agent_error(403, 'Invalid registration key'); + if (!hash_equals(AGENT_REGISTRATION_KEY, $regKey)) agent_error(403, 'Invalid registration key'); $hostname = trim($data['hostname'] ?? ''); $agentType = $data['agent_type'] ?? 'linux'; @@ -108,8 +113,9 @@ switch ($agentAction) { // Mark as delivered if ($commands) { - $ids = implode(',', array_column($commands, 'id')); - JarvisDB::query("UPDATE agent_commands SET status='delivered', delivered_at=NOW() WHERE id IN ($ids)"); + $cmdIds = array_column($commands, 'id'); + $placeholders = implode(',', array_fill(0, count($cmdIds), '?')); + JarvisDB::query("UPDATE agent_commands SET status='delivered', delivered_at=NOW() WHERE id IN ($placeholders)", $cmdIds); foreach ($commands as &$cmd) { $cmd['command_data'] = json_decode($cmd['command_data'] ?? '{}', true); } diff --git a/api/endpoints/chat.php b/api/endpoints/chat.php index 29d404b..9126e8c 100644 --- a/api/endpoints/chat.php +++ b/api/endpoints/chat.php @@ -581,7 +581,7 @@ if (!$reply && defined('GROQ_API_KEY') && GROQ_API_KEY) { ], CURLOPT_TIMEOUT => GROQ_TIMEOUT, CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYPEER => true, ]); $resp = curl_exec($ch); @@ -672,7 +672,7 @@ Respond as JARVIS. Voice readout: under 3 sentences unless detail is requested. 'Content-Type: application/json', ], CURLOPT_TIMEOUT => 30, - CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYPEER => true, ]); $resp = curl_exec($ch);