Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
19 changes: 11 additions & 8 deletions automation/ops/reconfigure_ksc_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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."
Expand All @@ -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)
Expand All @@ -91,22 +94,22 @@ 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():
run_logger.info(line.strip())
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}")
Expand Down
Loading