From ba31748043451001bc7b6fad78dfda43414c7374 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 04:47:34 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20Predictable=20Temporary=20File=20Vulnerability=20in=20?= =?UTF-8?q?reconfigure=5Fksc=5Fservice.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated automation/ops/reconfigure_ksc_service.py to generate a random UUID for the temporary config file name (/tmp/reconfig_ans_.txt). This prevents symlink attacks and race conditions where a malicious local user could pre-create the predictable file (/tmp/reconfig_ans.txt) in the world-writable /tmp directory to overwrite arbitrary files. Co-authored-by: mendsec <12684528+mendsec@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ automation/ops/reconfigure_ksc_service.py | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 726fdde..80c9012 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -78,3 +78,8 @@ **Vulnerability:** Shell command injection vulnerability identified when passing user-controlled or configured data directly into string-interpolated shell commands (e.g. `f'-u postgres psql -c "CREATE DATABASE {db} OWNER {config.db_user};"'`). Even when nested in double quotes within the python f-string, double-quotes in the substituted parameter break out of the shell quotes. **Learning:** Whenever parameters (such as configuration variables, database names, users) are injected into a string that will be evaluated by a shell (like `sudo -S {cmd}` or `-c "{query}"`), they must be properly escaped to ensure the shell treats them as a single literal argument. **Prevention:** Always use `shlex.quote()` on the full query string before interpolating it into the shell command string (e.g., `query = f"CREATE DATABASE {db} OWNER {config.db_user};"; cmd = f"-u postgres psql -c {shlex.quote(query)}"`) or use argument arrays where supported. + +## 2026-06-05 - [CRITICAL] Prevent Predictable Temporary File Vulnerability +**Vulnerability:** The script `automation/ops/reconfigure_ksc_service.py` was creating a temporary response file (`/tmp/reconfig_ans.txt`) via Paramiko SFTP with a predictable, hardcoded filename in a world-writable directory (`/tmp`). This exposes the system to symlink attacks or race conditions where a malicious local user could pre-create the file as a symlink to overwrite arbitrary files. +**Learning:** Hardcoding filenames for temporary files in shared directories like `/tmp` is insecure. The predictability of the filename leaves the application vulnerable to symlink attacks (CWE-377). +**Prevention:** Always append a random string (e.g., `uuid.uuid4().hex`) to temporary file names in shared directories to ensure the file path is unpredictable and unique. diff --git a/automation/ops/reconfigure_ksc_service.py b/automation/ops/reconfigure_ksc_service.py index 44c17f0..68e8292 100644 --- a/automation/ops/reconfigure_ksc_service.py +++ b/automation/ops/reconfigure_ksc_service.py @@ -4,6 +4,7 @@ """ import logging +import uuid from automation.python.config import KscConfig from automation.python.remote import connect_ksc_host, run_remote_sudo from automation.python.logging_utils import ( @@ -31,6 +32,8 @@ def reconfigure_ksc_service(config: KscConfig, apply: bool = False) -> None: apply=apply, ) + tmp_file_path = f"/tmp/reconfig_ans_{uuid.uuid4().hex}.txt" + # Conteúdo do arquivo de respostas (gerado dinamicamente com valores seguros) ans_content = f"""EULA_ACCEPTED=1 PP_ACCEPTED=1 @@ -59,13 +62,13 @@ def reconfigure_ksc_service(config: KscConfig, apply: bool = False) -> None: if not apply: run_logger.info( - "[CHECK] Seria gerado um arquivo de respostas KLAUTOANSWERS em '/tmp/reconfig_ans.txt' via SFTP (modo 0600)." + f"[CHECK] Seria gerado um arquivo de respostas KLAUTOANSWERS em '{tmp_file_path}' via SFTP (modo 0600)." ) run_logger.info( - "[CHECK] Seria executado: KLAUTOANSWERS=/tmp/reconfig_ans.txt /opt/kaspersky/ksc64/lib/bin/setup/postinstall.pl" + f"[CHECK] Seria executado: KLAUTOANSWERS={tmp_file_path} /opt/kaspersky/ksc64/lib/bin/setup/postinstall.pl" ) run_logger.info( - "[CHECK] O arquivo temporário '/tmp/reconfig_ans.txt' seria removido do servidor remoto." + f"[CHECK] O arquivo temporário '{tmp_file_path}' seria removido do servidor remoto." ) run_logger.info( "[CHECK] Os serviços (kladminserver_srv.service e ksc-web-console.service) seriam reiniciados." @@ -79,10 +82,10 @@ def reconfigure_ksc_service(config: KscConfig, apply: bool = False) -> None: # Upload do arquivo de respostas via SFTP de forma isolada e segura run_logger.info( - "Gerando arquivo de respostas em /tmp/reconfig_ans.txt via SFTP..." + f"Gerando arquivo de respostas em {tmp_file_path} via SFTP..." ) sftp = client.open_sftp() - f = sftp.file("/tmp/reconfig_ans.txt", "w") + f = sftp.file(tmp_file_path, "w") # Força permissão apenas de leitura/escrita pelo owner para evitar vazamento local f.chmod(0o600) f.write(ans_content) @@ -91,14 +94,14 @@ def reconfigure_ksc_service(config: KscConfig, apply: bool = False) -> None: # Executa postinstall.pl postinstall_cmd = ( - "KLAUTOANSWERS=/tmp/reconfig_ans.txt " + f"KLAUTOANSWERS={tmp_file_path} " "/opt/kaspersky/ksc64/lib/bin/setup/postinstall.pl" ) run_cmd = f"-E bash -c '{postinstall_cmd}'" log_json(run_logger, "run_command_start", cmd="postinstall.pl (silencioso)") out, err, status = run_remote_sudo( - client, f"-E bash -c '{postinstall_cmd}'", config.ksc_pass + client, run_cmd, config.ksc_pass ) if out: for line in out.splitlines(): @@ -106,7 +109,7 @@ def reconfigure_ksc_service(config: KscConfig, apply: bool = False) -> None: log_json(run_logger, "run_command_end", status=status, stderr=err) # Limpeza do arquivo temporário - client.exec_command("rm -f /tmp/reconfig_ans.txt") + client.exec_command(f"rm -f {tmp_file_path}") if status != 0: raise OpsError(f"Erro na execução do postinstall.pl: {err}")