Skip to content

Corrige vulnerabilidades de segurança apontadas pelo CodeQL#9

Open
Rossi-Luciano wants to merge 2 commits into
scieloorg:mainfrom
Rossi-Luciano:fix/security-codeql-issue-6
Open

Corrige vulnerabilidades de segurança apontadas pelo CodeQL#9
Rossi-Luciano wants to merge 2 commits into
scieloorg:mainfrom
Rossi-Luciano:fix/security-codeql-issue-6

Conversation

@Rossi-Luciano

Copy link
Copy Markdown

O que esse PR faz?

Corrige duas vulnerabilidades de segurança identificadas pelo GitHub Advanced Security (CodeQL) na revisão scieloorg/scielo-tools#15:

  1. Open redirect na rota de troca de idioma — o parâmetro next era usado diretamente como destino de redirecionamento sem validação, permitindo redirecionar o usuário para URLs externas maliciosas.
  2. Path injection no serviço de validação — o nome do arquivo enviado pelo usuário fluía para operações de sistema de arquivos, sendo classificado como risco de path traversal pelo CodeQL.

Os demais alertas (cookie injection e path injection nos testes) foram analisados e classificados como falsos positivos: o valor do cookie já é sanitizado por normalize_language() com whitelist estrita, e os caminhos nos testes são controlados pelo pytest (tmp_path).

Onde a revisão poderia começar?

  • src/spsvalidator/web/routes.py — função _safe_redirect_target() e uso na rota set_language
  • src/spsvalidator/services/validation_service.py — substituição do nome de arquivo do usuário por "package.zip" no caminho temporário

Como este poderia ser testado manualmente?

  1. pip install -e ".[dev]"
  2. pytest — todos os testes devem continuar passando
  3. Tentar acessar /language/en?next=https://google.com e confirmar que o redirecionamento vai para / e não para a URL externa
  4. Subir um pacote .zip com nome contendo caracteres especiais e confirmar que a validação ocorre normalmente

Algum cenário de contexto que queira dar?

Os alertas foram gerados pelo CodeQL durante a revisão do PR scieloorg/scielo-tools#15. Os dois alertas reais (py/url-redirection com severidade error e py/path-injection com severidade error) exigiam correção antes do merge. Os demais cinco alertas foram analisados e descartados como falsos positivos, com justificativa documentada na issue.

Screenshots

N/A

Quais são tickets relevantes?

Closes #6

Referências

Rossi-Luciano and others added 2 commits June 26, 2026 12:28
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
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")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rossi-Luciano não pode ser fixo. Recupere o nome do arquivo em uso

if next_url and next_url.startswith("/") and not next_url.startswith("//"):
return next_url
return url_for("web.index")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use uma solução mais apropriada que é adoção da função urlparse

from urllib.parse import urlparse  # No Python moderno, ou werkzeug.urls

def _safe_redirect_target(next_url: str | None) -> str:
    if not next_url:
        return url_for("web.index")
    
    # Faz o parsing da URL
    parsed_url = urlparse(next_url)
    
    # Se o netloc (host) estiver vazio, significa que é uma URL relativa (interna e segura)
    if not parsed_url.netloc and parsed_url.path.startswith("/"):
        return next_url
        
    return url_for("web.index")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Corrigir questões de segurança / qualidade

2 participants