Skip to content

[Segurança] Cookie de sessão do console emitido sem o atributo Secure e com validade de um ano #1124

Description

@elio-neto

Problema

A configuração de sessão sobrescreve explicitamente o padrão do h3 (secure: true) para secure: false,
e define maxAge de 365 dias. O console é servido sobre HTTPS em produção, portanto o único efeito da
mudança é permitir que o navegador envie o cookie de sessão também em requisições HTTP.

Por que é explorável

Um atacante em posição de rede ativa (Wi-Fi compartilhado, proxy intermediário, DNS envenenado) que
consiga induzir uma única requisição HTTP para o domínio captura o cookie e assume a sessão. Com maxAge
de um ano, a janela de uso da sessão capturada é de um ano — sem precisar de credencial alguma.

O httpOnly está correto e protege contra leitura por script, mas não contra captura em trânsito.

Evidência

packages/console/app/src/context/auth.ts:28-38:

export function useAuthSession() {
  return useSession<AuthSession>({
    password: Resource.ZEN_SESSION_SECRET.value,
    name: "auth",
    maxAge: 60 * 60 * 24 * 365,
    cookie: {
      secure: false,          // <-- sobrescreve o padrao true do h3
      httpOnly: true,
    },
  })
}

infra/console.ts:248-250 — o domínio de produção é servido sobre HTTPS:

new sst.cloudflare.x.SolidStart("Console", {
  domain,
  path: "packages/console/app",

infra/stage.ts:1-5domain é opencode.ai em produção.

Impacto

Sequestro de sessão por captura em trânsito. A sessão carrega todas as contas vinculadas e dá acesso a
todos os workspaces daquela conta (ver AuthSession em auth.ts:17-26). O maxAge de um ano significa
que a sessão capturada segue util por muito tempo depois do momento da captura.

Sugestão de correção

  1. Trocar para secure: true, ou remover a chave e herdar o padrão do h3.
  2. Declarar sameSite: "lax" explicitamente, em vez de depender do default.
  3. Reduzir maxAge para valor compatível com o risco (por exemplo 30 dias), com renovação por
    atividade.
  4. Se o false existe para permitir http://localhost em desenvolvimento, condicionar ao stage:
    secure: Resource.App.stage === "production". Melhor ainda: usar HTTPS local, já que o navegador
    aceita cookies Secure em localhost.

Critérios de aceite

  • O cookie de sessão é emitido com Secure em produção
  • sameSite é declarado explicitamente
  • maxAge reduzido e a decisão documentada; renovação por atividade implementada
  • Teste: a resposta de /auth/callback em produção contém Secure no header Set-Cookie

Labels sugeridas: security, media

Achado da auditoria estatica de seguranca do commit 0465a5d. Relatorio completo em docs/security-audit/relatorio-auditoria-seguranca.pdf.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions