From 0d8143920e8f323c542745c8806e1bed2afb878e Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Fri, 26 Jun 2026 12:28:18 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Corrige=20path=20injection=20no=20servi?= =?UTF-8?q?=C3=A7o=20de=20valida=C3=A7=C3=A3o=20(CodeQL=20alerts=209,=2010?= =?UTF-8?q?,=2011)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Substitui o uso do nome de arquivo fornecido pelo usuário como parte do caminho temporário por um nome fixo ("package.zip") - O nome original do arquivo continua sendo preservado na variável `filename` e usado apenas para armazenamento no banco de dados (campo `package_name`), sem nunca fluir para expressões de caminho do sistema de arquivos - Elimina o vetor de path injection nos alertas CodeQL: · alert 11: construção do zip_path a partir de input do usuário (linha 36) · alert 10: abertura do arquivo com caminho derivado de input do usuário (linha 14) · alert 9: verificação de existência de arquivo com caminho contaminado (linha 50) Por quê: o CodeQL rastreava o dado do usuário (uploaded_file.filename) até operações de sistema de arquivos, classificando como risco de path traversal. A separação entre nome para exibição e nome para uso em I/O elimina completamente esse fluxo de dados contaminado. Co-Authored-By: Claude Sonnet 4.6 --- spsvalidator/src/spsvalidator/services/validation_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spsvalidator/src/spsvalidator/services/validation_service.py b/spsvalidator/src/spsvalidator/services/validation_service.py index 7cf4379..3dd5bbe 100644 --- a/spsvalidator/src/spsvalidator/services/validation_service.py +++ b/spsvalidator/src/spsvalidator/services/validation_service.py @@ -32,7 +32,7 @@ def run_validation( if not filename.lower().endswith(".zip"): raise ValueError(zip_only_message or "Only SPS .zip files are supported.") with tempfile.TemporaryDirectory(prefix="spsvalidator-") as temp_dir: - zip_path = os.path.join(temp_dir, Path(filename).name) + zip_path = os.path.join(temp_dir, "package.zip") uploaded_file.save(zip_path) result = validate_sps_zip(zip_path) rows = result["rows"] From 77d060f355178509d4698cea677b633f08916ea8 Mon Sep 17 00:00:00 2001 From: Rossi-Luciano Date: Fri, 26 Jun 2026 12:29:16 -0300 Subject: [PATCH 2/2] Corrige open redirect na rota de troca de idioma (CodeQL alert 5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adiciona a função auxiliar `_safe_redirect_target()` que valida o parâmetro `next` antes de utilizá-lo como destino de redirecionamento - A função aceita apenas caminhos relativos internos: deve começar com "/" e não pode começar com "//" (que permitiria redirecionar para domínio externo) - Qualquer valor inválido ou ausente resulta em redirecionamento seguro para a rota principal (`web.index`) - Substitui o uso direto de `request.args.get("next")` na rota `set_language` pelo retorno validado de `_safe_redirect_target()` Por quê: sem a validação, um atacante poderia construir uma URL como `/language/en?next=https://site-malicioso.com` e redirecionar o usuário para fora da aplicação após a troca de idioma — vulnerabilidade classificada pelo CodeQL como "URL redirection from remote source" com severidade error. Co-Authored-By: Claude Sonnet 4.6 --- spsvalidator/src/spsvalidator/web/routes.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spsvalidator/src/spsvalidator/web/routes.py b/spsvalidator/src/spsvalidator/web/routes.py index c3294a5..ff595cc 100644 --- a/spsvalidator/src/spsvalidator/web/routes.py +++ b/spsvalidator/src/spsvalidator/web/routes.py @@ -41,6 +41,12 @@ def _render_index(**context): ) +def _safe_redirect_target(next_url: str | None) -> str: + if next_url and next_url.startswith("/") and not next_url.startswith("//"): + return next_url + return url_for("web.index") + + def _redirect_with_lang(endpoint: str, **values): response = make_response(redirect(url_for(endpoint, **values))) language = normalize_language(request.cookies.get("lang")) @@ -98,7 +104,7 @@ def download_csv(history_id: str): @web_blueprint.get("/language/") def set_language(language_code: str): language = normalize_language(language_code) - redirect_target = request.args.get("next") or url_for("web.index") + redirect_target = _safe_redirect_target(request.args.get("next")) response = make_response(redirect(redirect_target)) response.set_cookie("lang", language, max_age=60 * 60 * 24 * 365) return response