From 4be6e948b9365e6aad7c008ad6ffb05106e977df Mon Sep 17 00:00:00 2001 From: Open Source Contributor Date: Thu, 23 Apr 2026 11:07:06 -0600 Subject: [PATCH 1/3] security: fix yaml.load deprecation and SQL injection in database creation - Replace yaml.load() with yaml.safe_load() to prevent arbitrary code execution - Add validation for database names to prevent SQL injection in CREATE DATABASE statements - Use parameterized identifiers with backticks (MySQL) and quotes (PostgreSQL) --- nettacker/core/messages.py | 2 +- nettacker/database/mysql.py | 6 +++++- nettacker/database/postgresql.py | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/nettacker/core/messages.py b/nettacker/core/messages.py index 9f07cb730..af9d384ae 100644 --- a/nettacker/core/messages.py +++ b/nettacker/core/messages.py @@ -20,7 +20,7 @@ def application_language(): def load_yaml(filename): - return yaml.load(StringIO(open(filename, "r").read()), Loader=yaml.FullLoader) + return yaml.safe_load(open(filename, "r")) def get_languages(): diff --git a/nettacker/database/mysql.py b/nettacker/database/mysql.py index 98e433f1b..905fe5cd2 100644 --- a/nettacker/database/mysql.py +++ b/nettacker/database/mysql.py @@ -20,7 +20,11 @@ def mysql_create_database(): existing_databases = [d[0] for d in existing_databases] if Config.db.name not in existing_databases: - conn.execute(text("CREATE DATABASE {0} ".format(Config.db.name))) + db_name = Config.db.name + if db_name.isalnum() and db_name[0].isalpha(): + conn.execute(text(f"CREATE DATABASE `{db_name}` ")) + else: + raise ValueError(f"Invalid database name: {db_name}") except Exception as e: print(e) diff --git a/nettacker/database/postgresql.py b/nettacker/database/postgresql.py index d138e5045..04b6998e5 100644 --- a/nettacker/database/postgresql.py +++ b/nettacker/database/postgresql.py @@ -26,7 +26,11 @@ def postgres_create_database(): ) conn = engine.connect() conn = conn.execution_options(isolation_level="AUTOCOMMIT") - conn.execute(text(f"CREATE DATABASE {Config.db.name}")) + db_name = Config.db.name + if db_name.isalnum() and db_name[0].isalpha(): + conn.execute(text(f'CREATE DATABASE "{db_name}"')) + else: + raise ValueError(f"Invalid database name: {db_name}") conn.close() engine = create_engine( "postgresql+psycopg2://{username}:{password}@{host}:{port}/{name}".format( From 65e27fbe9948360d433460ec25d169be4607a017 Mon Sep 17 00:00:00 2001 From: Open Source Contributor Date: Thu, 23 Apr 2026 21:47:31 -0600 Subject: [PATCH 2/3] bugfix: fix file handle leaks in arg_parser.py and messages.py - Use context managers for all file open() calls to prevent resource leaks - Fix load_yaml() to properly close file handles - Fix file reading in targets_list, user_agents, usernames_list, passwords_list, and read_from_file --- nettacker/core/arg_parser.py | 17 ++++++++++------- nettacker/core/messages.py | 3 ++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/nettacker/core/arg_parser.py b/nettacker/core/arg_parser.py index 459d7c9b2..fcf882ca4 100644 --- a/nettacker/core/arg_parser.py +++ b/nettacker/core/arg_parser.py @@ -612,9 +612,8 @@ def parse_arguments(self): options.targets = list(set(options.targets.split(","))) if options.targets_list: try: - options.targets = list( - set(open(options.targets_list, "rb").read().decode().split()) - ) + with open(options.targets_list, "rb") as f: + options.targets = list(set(f.read().decode().split())) except Exception: die_failure(_("error_target_file").format(options.targets_list)) @@ -708,14 +707,16 @@ def parse_arguments(self): options.excluded_ports = list(tmp_excluded_ports) if options.user_agent == "random_user_agent": - options.user_agents = open(Config.path.user_agents_file).read().split("\n") + with open(Config.path.user_agents_file) as f: + options.user_agents = f.read().split("\n") # Check user list if options.usernames: options.usernames = list(set(options.usernames.split(","))) elif options.usernames_list: try: - options.usernames = list(set(open(options.usernames_list).read().split("\n"))) + with open(options.usernames_list) as f: + options.usernames = list(set(f.read().split("\n"))) except Exception: die_failure(_("error_username").format(options.usernames_list)) # Check password list @@ -723,13 +724,15 @@ def parse_arguments(self): options.passwords = list(set(options.passwords.split(","))) elif options.passwords_list: try: - options.passwords = list(set(open(options.passwords_list).read().split("\n"))) + with open(options.passwords_list) as f: + options.passwords = list(set(f.read().split("\n"))) except Exception: die_failure(_("error_passwords").format(options.passwords_list)) # Check custom wordlist if options.read_from_file: try: - open(options.read_from_file).read().split("\n") + with open(options.read_from_file) as f: + f.read().split("\n") except Exception: die_failure(_("error_wordlist").format(options.read_from_file)) # Check output file diff --git a/nettacker/core/messages.py b/nettacker/core/messages.py index af9d384ae..59fd035ac 100644 --- a/nettacker/core/messages.py +++ b/nettacker/core/messages.py @@ -20,7 +20,8 @@ def application_language(): def load_yaml(filename): - return yaml.safe_load(open(filename, "r")) + with open(filename, "r") as f: + return yaml.safe_load(f) def get_languages(): From f7b4bcc79a12f04e22c471856d0ebde0537035fa Mon Sep 17 00:00:00 2001 From: Open Source Contributor Date: Thu, 23 Apr 2026 21:48:23 -0600 Subject: [PATCH 3/3] security: add whitelist validation for SQLite PRAGMA settings - Add allowed_journal_modes and allowed_sync_modes whitelists - Validate Config.db.journal_mode and Config.db.synchronous_mode against whitelists - Raise ValueError if invalid values are provided This prevents potential SQL injection in PRAGMA statements. --- nettacker/database/db.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/nettacker/database/db.py b/nettacker/database/db.py index 3444db72f..834be07cf 100644 --- a/nettacker/database/db.py +++ b/nettacker/database/db.py @@ -60,8 +60,16 @@ def create_connection(): cursor = connection.cursor() # Performance enhancing configurations. Put WAL cause that helps with concurrency. - cursor.execute(f"PRAGMA journal_mode={Config.db.journal_mode}") - cursor.execute(f"PRAGMA synchronous={Config.db.synchronous_mode}") + allowed_journal_modes = {"DELETE", "WAL", "MEMORY", "OFF"} + allowed_sync_modes = {"OFF", "NORMAL", "FULL", "EXTRA"} + journal_mode = Config.db.journal_mode + sync_mode = Config.db.synchronous_mode + if journal_mode not in allowed_journal_modes: + raise ValueError(f"Invalid journal_mode: {journal_mode}") + if sync_mode not in allowed_sync_modes: + raise ValueError(f"Invalid synchronous_mode: {sync_mode}") + cursor.execute(f"PRAGMA journal_mode={journal_mode}") + cursor.execute(f"PRAGMA synchronous={sync_mode}") return connection, cursor except Exception as e: