From eca384e3387cfd7ea0991d68fe39d9bd7e71143b Mon Sep 17 00:00:00 2001 From: Vu Huy Nguyen <26673584+blaccod@users.noreply.github.com> Date: Sat, 24 Jan 2026 23:58:00 +0100 Subject: [PATCH 1/5] Set full command as default for dangerous binaries For commands that should not be blanket-allowed like curl or wget, set the "this command line only" as default target for rules --- ui/opensnitch/dialogs/prompt/constants.py | 1 + ui/opensnitch/dialogs/prompt/utils.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/ui/opensnitch/dialogs/prompt/constants.py b/ui/opensnitch/dialogs/prompt/constants.py index 7ecba064fe..985cedc940 100644 --- a/ui/opensnitch/dialogs/prompt/constants.py +++ b/ui/opensnitch/dialogs/prompt/constants.py @@ -39,6 +39,7 @@ APPIMAGE_PREFIX = "/tmp/.mount_" SNAP_PREFIX = "/snap" +FULL_COMMAND_BIN = ["python", "curl", "wget", "node", "java"] # label displayed in the pop-up combo DURATION_session = QC.translate("popups", "until reboot") diff --git a/ui/opensnitch/dialogs/prompt/utils.py b/ui/opensnitch/dialogs/prompt/utils.py index a362748cf9..3dd52c39fd 100644 --- a/ui/opensnitch/dialogs/prompt/utils.py +++ b/ui/opensnitch/dialogs/prompt/utils.py @@ -1,6 +1,7 @@ from slugify import slugify import os import ipaddress +from pathlib import Path from PyQt6.QtCore import QCoreApplication as QC @@ -230,6 +231,7 @@ def set_default_duration(cfg, durationCombo): def set_default_target(combo, con, cfg, app_name, app_args): # set appimage as default target if the process path starts with # /tmp/._mount + connection_path = Path(con.process_path) if con.process_path.startswith(constants.APPIMAGE_PREFIX): idx = combo.findData(constants.FIELD_APPIMAGE) if idx != -1: @@ -240,6 +242,11 @@ def set_default_target(combo, con, cfg, app_name, app_args): if idx != -1: combo.setCurrentIndex(idx) return + # entire command as default target for "dangerous" commands + # (e.g. curl, wget, node) + elif any(bin in connection_path.name for bin in constants.FULL_COMMAND_BIN): + combo.setCurrentIndex(1) + return saved_target = int(cfg.getSettings(cfg.DEFAULT_TARGET_KEY)) # In order to respect user selection, the app_name and app_args must be From 8a747e8fcd43b9038df859b8a218d79dfc11256c Mon Sep 17 00:00:00 2001 From: Vu Huy Nguyen <26673584+blaccod@users.noreply.github.com> Date: Sun, 25 Jan 2026 00:05:45 +0100 Subject: [PATCH 2/5] Match using startswith and not in to reduce potential false positives --- ui/opensnitch/dialogs/prompt/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/opensnitch/dialogs/prompt/utils.py b/ui/opensnitch/dialogs/prompt/utils.py index 3dd52c39fd..4f118446df 100644 --- a/ui/opensnitch/dialogs/prompt/utils.py +++ b/ui/opensnitch/dialogs/prompt/utils.py @@ -244,7 +244,7 @@ def set_default_target(combo, con, cfg, app_name, app_args): return # entire command as default target for "dangerous" commands # (e.g. curl, wget, node) - elif any(bin in connection_path.name for bin in constants.FULL_COMMAND_BIN): + elif any(connection_path.name.startswith(bin) for bin in constants.FULL_COMMAND_BIN): combo.setCurrentIndex(1) return From 85e8d26040ead6ad02596dad582dfe0667ba10d4 Mon Sep 17 00:00:00 2001 From: Vu Huy Nguyen <26673584+blaccod@users.noreply.github.com> Date: Sun, 25 Jan 2026 00:09:48 +0100 Subject: [PATCH 3/5] ssh is also dangerous --- ui/opensnitch/dialogs/prompt/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/opensnitch/dialogs/prompt/constants.py b/ui/opensnitch/dialogs/prompt/constants.py index 985cedc940..b5b75a8361 100644 --- a/ui/opensnitch/dialogs/prompt/constants.py +++ b/ui/opensnitch/dialogs/prompt/constants.py @@ -39,7 +39,7 @@ APPIMAGE_PREFIX = "/tmp/.mount_" SNAP_PREFIX = "/snap" -FULL_COMMAND_BIN = ["python", "curl", "wget", "node", "java"] +FULL_COMMAND_BIN = ["python", "curl", "wget", "node", "java", "ssh"] # label displayed in the pop-up combo DURATION_session = QC.translate("popups", "until reboot") From ab5f326e69c851fcd4d0bb4ed7ad54f741f10493 Mon Sep 17 00:00:00 2001 From: Vu Huy Nguyen <26673584+blaccod@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:19:20 +0200 Subject: [PATCH 4/5] add UI to configure the list in settings --- ui/opensnitch/config.py | 1 + ui/opensnitch/dialogs/preferences/settings.py | 11 +++++++++ ui/opensnitch/dialogs/prompt/utils.py | 10 +++++++- ui/opensnitch/res/preferences.ui | 23 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/ui/opensnitch/config.py b/ui/opensnitch/config.py index d5ae2e5c6d..4d0bd4e8b9 100644 --- a/ui/opensnitch/config.py +++ b/ui/opensnitch/config.py @@ -111,6 +111,7 @@ class Config: DEFAULT_POPUP_ADVANCED_CHECKSUM = "global/default_popup_advanced_checksum" DEFAULT_FW_INTERCEPTION_ENABLED = "global/interception_enabled" DEFAULT_PERSIST_INTERCEPTION_STATE = "global/persist_interception_state" + DEFAULT_POPUP_ADVANCED_FULL_COMMAND = "global/default_popup_advanced_full_command" DEFAULT_SERVER_ADDR = "global/server_address" DEFAULT_SERVER_MAX_MESSAGE_LENGTH = "global/server_max_message_length" DEFAULT_SERVER_MAX_WORKERS = "global/max_workers" diff --git a/ui/opensnitch/dialogs/preferences/settings.py b/ui/opensnitch/dialogs/preferences/settings.py index bd4b586128..00aff75e1c 100644 --- a/ui/opensnitch/dialogs/preferences/settings.py +++ b/ui/opensnitch/dialogs/preferences/settings.py @@ -9,6 +9,7 @@ from opensnitch.config import Config from opensnitch.utils import languages from opensnitch.database import Database +from opensnitch.dialogs.prompt import constants as prompt_constants from opensnitch.dialogs.preferences import ( utils, ) @@ -59,6 +60,15 @@ def load(win): win.uidCheck.setChecked(win.cfgMgr.getBool(win.cfgMgr.DEFAULT_POPUP_ADVANCED_UID)) win.checkSum.setChecked(win.cfgMgr.getBool(win.cfgMgr.DEFAULT_POPUP_ADVANCED_CHECKSUM)) + default_full_cmds = ",".join(prompt_constants.FULL_COMMAND_BIN) + if win.cfgMgr.hasKey(win.cfgMgr.DEFAULT_POPUP_ADVANCED_FULL_COMMAND): + full_cmds = win.cfgMgr.getSettings(win.cfgMgr.DEFAULT_POPUP_ADVANCED_FULL_COMMAND) + if full_cmds is None: + full_cmds = "" + else: + full_cmds = default_full_cmds + win.fullCommandBin.setText(str(full_cmds)) + ## rules win.comboUIRules.blockSignals(True) win.comboUIRules.setCurrentIndex(win.cfgMgr.getInt(win.cfgMgr.DEFAULT_IGNORE_TEMPORARY_RULES)) @@ -211,6 +221,7 @@ def save_ui_config(win): win.cfgMgr.setSettings(win.cfgMgr.DEFAULT_POPUP_ADVANCED_DSTPORT, bool(win.dstPortCheck.isChecked())) win.cfgMgr.setSettings(win.cfgMgr.DEFAULT_POPUP_ADVANCED_UID, bool(win.uidCheck.isChecked())) win.cfgMgr.setSettings(win.cfgMgr.DEFAULT_POPUP_ADVANCED_CHECKSUM, bool(win.checkSum.isChecked())) + win.cfgMgr.setSettings(win.cfgMgr.DEFAULT_POPUP_ADVANCED_FULL_COMMAND, win.fullCommandBin.text()) win.cfgMgr.setSettings(win.cfgMgr.NOTIFICATIONS_ENABLED, bool(win.groupNotifs.isChecked())) win.cfgMgr.setSettings(win.cfgMgr.NOTIFICATIONS_TYPE, diff --git a/ui/opensnitch/dialogs/prompt/utils.py b/ui/opensnitch/dialogs/prompt/utils.py index 4f118446df..791dd60283 100644 --- a/ui/opensnitch/dialogs/prompt/utils.py +++ b/ui/opensnitch/dialogs/prompt/utils.py @@ -228,6 +228,14 @@ def set_default_duration(cfg, durationCombo): else: durationCombo.setCurrentIndex(Config.DEFAULT_DURATION_IDX) +def _get_full_command_bins(cfg): + if cfg.hasKey(cfg.DEFAULT_POPUP_ADVANCED_FULL_COMMAND): + full_cmds = cfg.getSettings(cfg.DEFAULT_POPUP_ADVANCED_FULL_COMMAND) + if full_cmds is not None: + return [x.strip() for x in full_cmds.split(",") if x.strip()] + return [] + return constants.FULL_COMMAND_BIN + def set_default_target(combo, con, cfg, app_name, app_args): # set appimage as default target if the process path starts with # /tmp/._mount @@ -244,7 +252,7 @@ def set_default_target(combo, con, cfg, app_name, app_args): return # entire command as default target for "dangerous" commands # (e.g. curl, wget, node) - elif any(connection_path.name.startswith(bin) for bin in constants.FULL_COMMAND_BIN): + elif any(connection_path.name.startswith(bin) for bin in _get_full_command_bins(cfg)): combo.setCurrentIndex(1) return diff --git a/ui/opensnitch/res/preferences.ui b/ui/opensnitch/res/preferences.ui index 8b05b413c6..a4b6d88c25 100644 --- a/ui/opensnitch/res/preferences.ui +++ b/ui/opensnitch/res/preferences.ui @@ -546,6 +546,29 @@ + + + + + 0 + 0 + + + + Full command by default + + + Comma-separated list of commands that will be selected by default in the pop-up dialog. + + + + + + + e.g. python, curl (leave empty to disable) + + + From 0866052c81372763727981d5a219866f20979654 Mon Sep 17 00:00:00 2001 From: Vu Huy Nguyen <26673584+blaccod@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:28:18 +0200 Subject: [PATCH 5/5] Update UI writing to be more clear --- ui/opensnitch/res/preferences.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/opensnitch/res/preferences.ui b/ui/opensnitch/res/preferences.ui index a4b6d88c25..fb0154b494 100644 --- a/ui/opensnitch/res/preferences.ui +++ b/ui/opensnitch/res/preferences.ui @@ -555,17 +555,17 @@ - Full command by default + Filter by full command by default - Comma-separated list of commands that will be selected by default in the pop-up dialog. + List of commands that will be selected to filter as "from this command line" by default in the pop-up dialog. The list should be comma-separated without spaces. It would match all commands that starts with a word in the list. - e.g. python, curl (leave empty to disable) + e.g. python,curl (leave empty to disable)