Política de segurança
O Herkos trata chaves privadas e mensagens cifradas, por isso levamos a sério as comunicações de segurança e preferimos saber de um problema cedo do que tarde.
Comunicar uma vulnerabilidade
Por favor, não abra uma issue pública para problemas de segurança.
Comunique-o em privado por email para security@herkos.email.
O que convém incluir: qual é o problema, como reproduzi-lo, em que plataforma e versão o testou, e o que um atacante conseguiria fazer. Uma prova de conceito ajuda muito.
Nunca inclua num relatório a sua própria nsec, chave secreta ou segredo do bunker.
Procuramos confirmar a receção dos relatórios em poucos dias. Como o Herkos é um projeto pequeno, conceda-nos um prazo razoável para uma correção antes de o divulgar publicamente. Teremos todo o gosto em creditá-lo no aviso, salvo se preferir o contrário.
O que está abrangido
A própria aplicação Herkos: tratamento e armazenamento de chaves, cifragem e
decifragem de mensagens (incluindo as verificações do remetente NIP-59 e o isolamento do Bcc
em local_packages/nostr_mail), o bloqueio da aplicação, a comunicação com relays e bridges,
o tratamento de anexos, e o processo de compilação e publicação.
No Herkos Drive, também o seu pacote de protocolo
(packages/herkos_drive_protocol) e a página que abre as suas ligações
(herkos.app/f/); ver a secção própria mais abaixo.
O que não está abrangido
- O protocolo Nostr e os seus NIPs em si — comunique esses problemas a montante.
- Relays, bridges e servidores Blossom operados por terceiros. O Herkos vem com predefinições mas não os opera; comunique os problemas aos respetivos operadores.
- O projeto original Nostr Mail Client, salvo se o problema for específico de alterações feitas no Herkos.
- Falta de reforço que já documentamos como limitação conhecida (ver abaixo).
Limitações conhecidas, ditas com clareza
São compromissos de conceção, não vulnerabilidades. Preferimos escrevê-los a que alguém os descubra da pior maneira:
- O correio para endereços tradicionais não é cifrado ponta a ponta. As mensagens entre utilizadores do Nostr usam gift wrap NIP-17 e são cifradas ponta a ponta. Quando escreve para um endereço de email comum, um bridge converte a mensagem e consegue lê-la.
- O bloqueio da aplicação (PIN e biometria) é uma barreira de conveniência, não cifragem em repouso. Impede quem pegue num dispositivo desbloqueado; não protege contra um atacante com acesso total ao dispositivo ou ao seu armazenamento.
- No Windows, não é possível impor autenticação apenas biométrica. O Windows Hello não permite escolher o método, por isso o PIN do sistema fica sempre disponível como alternativa.
- Perder a chave significa perder a conta. Não há recuperação, por conceção.
- Os metadados não ficam totalmente ocultos. Os relays podem observar padrões de ligação, e todos os relays veem o seu endereço IP, mesmo quando não conseguem ler o conteúdo das mensagens. O que o Herkos não revela (desde 30-09-2026) é quem escreve a quem quando um relay pede autenticação NIP-42:
- Procurar onde entregar. As listas de relays e de servidores Blossom de um destinatário
são pedidas numa ligação separada que nunca o identifica, primeiro em
relays que não exigem autenticação (
purplepag.es,user.kindpag.es,nos.lol,offchain.pub). - Perfis e o agendador. O nome e a imagem mostrados para qualquer outra pessoa (kind 0), e a lista de relays do DVM de agendamento quando agenda ou cancela um email, são pedidos da mesma forma: primeiro de forma anónima e, se um relay insistir, com a chave temporária descrita abaixo, nunca com a sua (desde 01-10-2026; antes, um relay que pedisse autenticação recebia a sua chave, e podia saber de quem era o perfil que estava a ver). Só o seu próprio perfil continua a ser lido em seu nome.
- Entregar. Os gift wraps vão para os relays DM do destinatário, nessa mesma ligação separada. Se um deles exigir autenticação, o Herkos responde com uma chave criada para o efeito e guardada apenas em memória, nunca com a sua; cada conta no dispositivo tem a sua. O relay continua a poder ver que o mesmo dispositivo (mesmo IP, mesma chave temporária) enviou vários envelopes durante uma sessão.
- Emails grandes. A cópia cifrada de um email com mais de 32 KB é enviada para servidores Blossom, incluindo os dos destinatários. Só os seus próprios servidores (a sua lista Blossom) recebem o envio autorizado com a sua chave. Qualquer outro servidor recebe-o de forma anónima e, se insistir numa autorização, uma assinada com a mesma chave temporária de cima (desde 01-10-2026; antes, todos os servidores recebiam a sua chave). Um servidor que só aceite chaves conhecidas recusa-o, e a cópia fica nos outros servidores.
- Os seus próprios dados. A sincronização da sua caixa de correio, etiquetas, definições e rascunhos autentica-se, quando um relay o pede, como a conta a que os dados pertencem, mesmo durante uma mudança de conta. Nos seus próprios relays isso não lhes diz nada que não soubessem: os pedidos já nomeiam a sua chave. As suas próprias listas de relays e de servidores Blossom são públicas e são pedidas sem o identificar, tal como os relays indicados numa ligação de email.
- O estado de leitura e as pastas são metadados públicos (por agora). Marcar um email como lido, destacado, arquivado ou movido publica um evento de etiqueta NIP-32 não cifrado ligado à sua chave pública, incluindo os nomes das pastas próprias. Um remetente que conheça o identificador de um email que lhe enviou consegue saber quando agiu sobre ele. Cifrar estas etiquetas está previsto; até lá, considere públicos os nomes das pastas.
- As notificações push e o envio agendado usam serviços de terceiros. O
servidor push, se escolher um (nenhum por predefinição;
api.nmail.licomrelay.nmail.lise o pedir), fica a saber a sua chave pública, um token push e quando recebe correio; o DVM de agendamento fica a saber a sua chave pública e as mensagens já cifradas que tem de publicar. Ambos são opcionais e estão documentados noPRIVACY.md. O texto de uma notificação push é escolhido pelo servidor push, e o Herkos só confia nele quando o UnifiedPush o entrega cifrado (RFC 8291); um conteúdo não cifrado apenas acorda a aplicação para ir buscar o correio ela própria. - A versão web guarda a sua chave no navegador, que é o sítio mais fraco para ela. As aplicações instaladas entregam a sua chave secreta ao armazenamento seguro do sistema operativo (Android Keystore, DPAPI no Windows, libsecret, o porta-chaves do iOS/macOS). Um navegador não tem nada disso: a chave fica no armazenamento da origem e passa pelo JavaScript em cada assinatura, ao alcance de qualquer código que corra na página — uma extensão do navegador com acesso a todos os sites, uma falha de XSS na aplicação ou numa dependência, uma implantação adulterada — e de qualquer infostealer que copie o perfil do navegador. Também não existe nenhum momento em que verifique o código uma vez: um binário assinado é verificado na instalação, enquanto uma página web envia código novo em cada visita. Entre na versão web com um assinante remoto (bunker NIP-46, Amber), para que a chave nunca chegue ao navegador, ou trate-a como uma identidade descartável e guarde a sua chave verdadeira numa aplicação instalada.
- O correio que passa por um bridge só é tão fiável quanto o bridge. O Herkos verifica que uma
mensagem marcada como vinda através de um bridge foi mesmo assinada por um bridge que
configurou (ou um dos predefinidos). Não consegue verificar nada sobre o
endereço
From:tradicional que o bridge transmite. - Os anexos são abertos pelo sistema operativo. O Herkos nunca executa tipos de ficheiro executáveis ou de script e pergunta antes de entregar qualquer outro anexo sem pré-visualização à aplicação predefinida do sistema, mas a aplicação que abre o ficheiro está fora do nosso controlo.
Herkos Local Relay: o que protege e o que não protege
O Herkos Local Relay guarda no seu dispositivo os eventos das suas aplicações, também os privados (rascunhos, listas privadas, os envelopes que recebe). Isto é o que os protege e onde está o limite, plataforma a plataforma. Os problemas de segurança do relay comunicam-se como os outros (acima).
A base de dados é cifrada por inteiro, incluindo o diário (SQLite3 Multiple Ciphers, AEGIS-256). A chave são 32 bytes aleatórios criados no dispositivo e guardados no armazenamento seguro do sistema: o Keystore no Android, a DPAPI no Windows, o porta-chaves (libsecret) no Linux. Não leva nenhuma palavra-passe sua, porque o relay tem de arrancar sozinho. Sem a chave, o relay não arranca e diz porquê: nunca abre nem cria uma base não cifrada, e nunca apaga a que não consegue abrir.
| Se… | Android | Windows | Linux |
|---|---|---|---|
| alguém copia o ficheiro da base (uma cópia de segurança, uma pasta sincronizada, uma imagem do disco) | Protegido | Protegido | Protegido |
| lhe roubam o aparelho ou o disco desligado | Protegido: a chave está no Keystore | Protegido, a menos que saibam a palavra-passe da sua sessão do Windows: a DPAPI protege a chave com ela | Protegido, a menos que saibam a palavra-passe do seu porta-chaves (quase sempre, a da sua sessão) |
| outra conta de utilizador do mesmo aparelho | Protegido | Protegido: a DPAPI é por utilizador | Protegido: o porta-chaves é por utilizador |
| outra aplicação ou programa a correr com o seu utilizador | Protegido: o Android isola cada aplicação e o Keystore só dá a chave ao relay | Não: a DPAPI cifra por utilizador, não por aplicação; um programa que corre como o utilizador pode pedir a chave tal como o relay | Não: o porta-chaves da sua sessão não separa as aplicações umas das outras |
| um telemóvel com root, ou uma ferramenta que executa código como a aplicação | Não | — | — |
| alguém tem o aparelho desbloqueado na mão | Só com o PIN ou a impressão digital do relay, se os definir | Igual | Igual |
| alguém lê a memória do relay enquanto funciona | Não | Não | Não |
No computador, o limite da DPAPI e do porta-chaves é o de qualquer programa: protegem contra outros utilizadores e contra quem leva o disco, não contra um programa malicioso que já corre com o seu utilizador. Se esse caso o preocupa, o que protege é a cifragem do disco do sistema (BitLocker, LUKS) juntamente com não executar programas em que não confia. Num Linux sem porta-chaves (sem Secret Service), o relay não arranca e explica porquê: nunca guarda a chave em claro.
Quem entra, no próprio dispositivo. O relay só escuta em 127.0.0.1, e
qualquer aplicação do dispositivo, ou uma página web do navegador, consegue
chegar a esse endereço. Por isso:
- Uma aplicação tem de ser emparelhada: aparece no ecrã do relay e é o utilizador que a aprova (com o PIN ou a impressão digital, se os definiu). Qualquer aplicação pode dar a si própria qualquer nome: aprove só se acabou de o pedir a partir dessa aplicação.
- Uma página web é sempre emparelhada, e um emparelhamento só vale a partir de onde foi feito: o de uma aplicação do dispositivo não abre nada a uma página web, mesmo que assine com a mesma chave.
- Uma aplicação emparelhada só lê e escreve os tipos de evento que lhe deu, e só apaga os que pode escrever. Revogá-la desliga-a de imediato.
- Uma aplicação não emparelhada só lê os seus eventos públicos (que já são públicos) e não escreve nada, a menos que ative a definição que deixa entrar as aplicações do dispositivo não emparelhadas.
- Os eventos privados só são entregues a quem provar com NIP-42 que tem a chave a que pertencem, e um envelope, só ao seu destinatário.
O que não protege, aqui:
- Uma aplicação maliciosa do dispositivo pode tornar o relay mais lento ou fazê-lo gastar memória. Não consegue, com isso, ler nada privado.
- Enquanto o relay dorme ou não está a funcionar, a porta fica livre. No Android, adormece após 10 minutos sem ligações; no computador, a porta está livre enquanto não o arrancar. Outra aplicação poderia escutar aí e fazer-se passar por ele. As aplicações Herkos vão verificar a chave do relay antes de lhe enviarem algo privado; ainda não o fazem, e até lá isto é um limite real.
- No computador, outros utilizadores da máquina podem ligar-se como uma aplicação não emparelhada: ler os seus eventos públicos e pedir para emparelhar.
A rede local, se a ativar (vem desativada):
- Só
wss://, com um certificado próprio do relay; nuncaws://não cifrado fora do dispositivo. - Nada antes de se autenticar (NIP-42) com uma chave da sua lista. Uma ligação que não o faça em 30 segundos é fechada, e a rede local tem um número de ligações próprio: nunca ocupa as das aplicações do dispositivo.
- Uma chave da lista lê os seus eventos públicos e os privados dela, e só escreve eventos assinados por ela. Retirá-la da lista desliga-a.
- O certificado só vale para nomes de casa (
localhost,.local, endereços privados): mesmo que alguém roubasse a chave dele, não lhe serviria para assinar um domínio da Internet nos aparelhos que o instalaram.
O que não protege, aqui: quem está na mesma rede vê que o aparelho tem uma porta aberta e quanto tráfego passa, mas não o que passa; e se o aparelho tem um endereço público (sem router pelo meio), essa porta vê-se a partir da Internet, embora continue a pedir uma chave da sua lista.
Cópias. A cópia cifrada tem palavra-passe (scrypt e XChaCha20-Poly1305): sem ela ninguém a consegue abrir, nem nós. A exportação JSONL não é cifrada e contém os seus eventos privados em claro; a aplicação avisa.
O bloqueio (PIN, e impressão digital ou Windows Hello) é pedido ao abrir a aplicação, após 30 segundos fora, e para aprovar um emparelhamento. É uma barreira de conveniência, como no Mail: não cifra nada. No Android, com PIN definido não há capturas de ecrã nem miniatura nas aplicações recentes, e desde o Android 12 nenhuma janela de outra aplicação se pode sobrepor à do relay enquanto a usa.
Herkos Drive: o que protege e o que não protege
O Herkos Drive guarda os seus ficheiros em servidores Blossom e a lista dos
seus ficheiros e pastas em relays Nostr, ambos cifrados no seu dispositivo. É
isto que os protege, e estes são os limites. O detalhe completo está em
spec-drive.md e no modelo de ameaças amenazas-drive.md, em
packages/herkos_drive_protocol/; o que cada relay e cada servidor vê está na
política de privacidade. Comunique os
problemas de segurança do Drive da mesma forma que os outros (acima).
O que os relays e os servidores não conseguem fazer:
- Ler os seus ficheiros ou os nomes deles. Cada bloco de um ficheiro é cifrado com AES-256-GCM com uma chave própria da sua revisão; nomes, pastas, tamanhos, datas e chaves vão selados com XChaCha20-Poly1305 com a chave da pasta onde estão. Nada é derivado do conteúdo: o mesmo ficheiro carregado duas vezes dá blocos diferentes.
- Alterar, trocar ou mover algo sem se notar. Cada bloco é verificado contra o manifesto selado na entrada do seu ficheiro, e cada entrada é assinada pela chave do volume e selada para o seu próprio lugar (volume, identificador e pasta): um relay não consegue fazer passar uma entrada por outra, nem um bloco por outro.
- Repor uma versão antiga. A aplicação nunca aceita uma entrada mais antiga do que a que já tem para o mesmo identificador.
- Escrever em seu nome só com a chave do volume. O que os seus dispositivos escrevem leva a marca do proprietário, um HMAC com uma chave que nenhuma ligação dá; uma entrada ou um apagamento sem ela não é aceite, e a aplicação avisa-o.
O que não protege:
- O padrão do seu Drive. Os relays podem contar os seus ficheiros e pastas, ver a forma da árvore e quando cada entrada muda; os servidores veem aproximadamente o tamanho de cada ficheiro (os blocos são preenchidos até 64 KiB, as entradas até uma potência de dois). Cada relay e cada servidor vê o seu endereço IP. Use Tor ou Orbot ao nível do sistema se isso lhe importar.
- O que alguém já transferiu. Remover uma ligação, ou uma pessoa, dá de imediato chaves novas ao que essa pessoa podia abrir, pelo que não abre o que acrescentar depois; não pode recuperar o que ela já guardou.
- Uma ligação divulgada. Uma ligação sem palavra-passe é a chave. O navegador pode guardá-la no histórico antes de a página a retirar da barra de endereço. Para tudo o que for sensível, dê à ligação uma palavra-passe, enviada por outra via, ou partilhe com a conta da pessoa. Uma palavra-passe fraca pode ser quebrada com tempo: quem tem a ligação pode tentar offline.
- A página
herkos.app/f/corre no navegador de quem abre uma ligação. É servida com uma Content-Security-Policy estrita, Subresource Integrity e nenhum código de terceiros, mas quem controlar o alojamento web poderia servir uma página diferente. É o limite de qualquer página web que decifra no navegador. - Quem teve a chave do volume (a sua, ou a dada com uma ligação para uma pasta) ainda pode apagar os blocos que foram carregados com ela, até serem carregados de novo. Pode mudar a chave do volume (Definições → Chave do volume): os seus outros dispositivos acompanham sozinhos.
- O seu dispositivo. A lista de ficheiros fica em cache cifrada, com a chave no armazenamento seguro do sistema; um ficheiro que transfira ou abra é escrito em claro onde escolher. O PIN do Drive é uma barreira de conveniência, como no Mail.
- Um computador quântico, mais tarde. Os blocos e os selos são simétricos (AES-256, XChaCha20), mas o seu localizador é cifrado com NIP-44 sobre secp256k1: quem o guarde hoje e quebre secp256k1 amanhã poderia abrir o Drive inteiro.
Como é verificado. Duas revisões internas face ao modelo de ameaças (2 de novembro de 2026) e as respetivas correções; testes do que mostra cada evento e cada bloco; fuzzing de cada leitor do que vem de fora (eventos, selos, manifestos, ligações, cópias de segurança). Ainda sem auditoria externa: há uma prevista antes da beta pública, e o relatório será publicado na íntegra. O Drive ainda está em desenvolvimento.
Versões suportadas
As correções de segurança são aplicadas à última versão publicada. Dada a dimensão do projeto, as versões anteriores não são mantidas — atualize antes de comunicar um problema.