Checklist de auditoria interna pré-externa
Diátaxis: explanation. Audiência: auditor externo de segurança
contratado para revisar o Anotae antes da v1.0 GA.
Este documento mapeia cada uma das 43 ameaças do
THREAT-MODEL.md para a evidência concreta
(arquivo, teste, commit) que o auditor pode verificar.
Para cada item:
- ID — referência STRIDE ou LINDDUN do threat model.
- Mitigação declarada — o que dizemos que fazemos.
- Onde verificar — arquivo + linha aproximada.
- Como auditor confirma — comando ou inspeção sugerida.
- Status auditoria — preenchido pelo auditor externo
(vazio até agora — auditoria pendente, dependente de
financiamento conforme item v0.9 BACKLOG).
Este checklist é vivo . Atualize quando uma mitigação mudar de
arquivo ou ganhar novo teste.
Legenda de Status auditoria
Símbolo
Significado
—
Não auditado ainda (default)
✅
Auditor verificou e mitigação está correta
⚠
Auditor identificou gap — mitigação parcial ou incompleta
❌
Auditor identificou falha — mitigação não funciona como declarado
🔄
Auditor sugeriu refinamento — issue/PR aberto para tratar
Quando preencher: auditor adiciona uma linha após cada tabela com
texto livre justificando ⚠/❌/🔄, com referência (data, número de
relatório de auditoria). Mudanças nesse arquivo passam por PR
normalmente — auditor envia patch.
Como o auditor preenche
Cloning + setup :
git clone https://github.com/carlosefdeavila/anotae.git
cd anotae
bash scripts/maintainer-onboard.sh # ~5 min
Para cada linha : rodar o "Comando auditor" da tabela e
verificar a evidência. Adicionar coluna "Status" preenchida
com símbolo apropriado.
Patch : PR com tabelas atualizadas + nova subseção
"Resultado da auditoria — \<DATA>" listando ⚠/❌/🔄 em
ordem de severidade.
STRIDE
S-1 — Usuário malicioso assume identidade do operador
Item
Detalhe
Mitigação
Vault cifrado por senha-mestra; CFM 2.454/2026 obriga revisão humana
Onde verificar
anotae/persistence/vault.py:open_vault linha ~110 + sei_inject_dialog.py
Comando auditor
pytest tests/integration/test_vault.py -k password
S-2 — Extensão maliciosa se passa pela Anotae no NMH
Item
Detalhe
Mitigação
Extension ID determinístico via key MV3 + allowed_origins em manifest
Onde verificar
extension/chrome/manifest.json (key fixa) + anotae/nmh/manifest.py:ALLOWED_ORIGINS_CHROME
Comando auditor
python -m anotae extension-info (mostra ID esperado) + verificar que chrome://extensions mostra mesmo ID
S-3 — App falso responde no HTTP loopback
Item
Detalhe
Mitigação
Token efêmero; binding 127.0.0.1; rejeita request sem header
Onde verificar
anotae/http_bridge/server.py
Comando auditor
pytest tests/integration/test_http_bridge.py
S-4 — Site malicioso assume identidade do e-SUS/SISREG/SEI
Item
Detalhe
Mitigação
host_permissions whitelist em manifest.json
Onde verificar
extension/chrome/manifest.json:host_permissions
Comando auditor
jq '.host_permissions' extension/chrome/manifest.json
T-1 — Adulteração do vault.db em disco
Item
Detalhe
Mitigação
ChaCha20-Poly1305 AEAD detecta tampering; SHA-256 por encounter em hash_sha256
Onde verificar
anotae/persistence/crypto.py:encrypt_field + compute_encounter_hash
Comando auditor
pytest tests/security/test_crypto_invariants.py
T-2 — MITM em mensagens NMH
Item
Detalhe
Mitigação
Por design — stdin/stdout do processo filho, sem rede
Onde verificar
anotae/nmh/handler.py
Comando auditor
grep -n "socket\|http\|net" anotae/nmh/ (esperado: zero matches)
T-3 — Adulteração de release binário
Item
Detalhe
Mitigação
Sigstore PEP 740 keyless via OIDC do GitHub Actions
Onde verificar
.github/workflows/build-windows.yml:Generate Sigstore attestation (PR #32)
Comando auditor
bash scripts/release-attestation.sh verify dist/Anotae-windows-x64.zip
T-3b — Adulteração de release não detectada por chave comprometida
Item
Detalhe
Mitigação
Build reproduzível via SOURCE_DATE_EPOCH permite verificar byte-a-byte
Onde verificar
.github/workflows/build-windows.yml:Build desktop app (PR #53)
Comando auditor
bash scripts/verify-reproducible.sh (clonar release, rodar, comparar SHA-256)
T-4 — Adulteração de dependência via supply chain
Item
Detalhe
Mitigação
pip-audit + Dependabot + lock file com hashes; SBOM CycloneDX
Onde verificar
pyproject.toml + .github/dependabot.yml + dist/sbom.json (gerado em CI)
Comando auditor
bash scripts/generate-sbom.sh && jq '.components | length' dist/sbom.json
Item
Detalhe
Mitigação
Append-only por contrato API; details cifrados field-level (defesa em profundidade)
Onde verificar
anotae/persistence/audit_log_repository.py (sem UPDATE/DELETE expostos)
Comando auditor
grep -n "UPDATE\|DELETE FROM audit_log" anotae/ (esperado: zero matches)
Limitação
Atacante com acesso ao SQLite raw pode editar — limitação aceita do modelo offline
T-6 — Hash do encounter não verificado ao ler
Item
Detalhe
Mitigação
Verificação automática (parcial) ao carregar
Onde verificar
anotae/persistence/repository.py
Comando auditor
pytest tests/security/test_crypto_invariants.py -k hash
Status
Cobertura parcial — gap reconhecido
R-1 — Profissional nega ter editado encounter
Item
Detalhe
Mitigação
Audit log no vault registra encounter.{created,updated,deleted} com timestamp + actor_cns
Onde verificar
anotae/persistence/audit_log_repository.py + ui/views/audit_history_dialog.py (Ctrl+H)
Comando auditor
Abrir vault, criar encounter, ir em Vault → Histórico (Ctrl+H), confirmar entrada
R-2 — Atacante apaga audit log para esconder rastro
Item
Detalhe
Mitigação
Limitação aceita — modelo offline sem servidor independente
Onde verificar
docs/THREAT-MODEL.md seção R-2
Comando auditor
Verificar que documentação aceita explicitamente esta limitação
R-3 — Profissional nega uso de IA na geração
Item
Detalhe
Mitigação
Disclaimer obrigatório em sei_inject_dialog; metadata.ai_assisted
Onde verificar
anotae/ui/views/sei_inject_dialog.py:DISCLAIMER + anotae/core/models.py:EncounterMetadata
Comando auditor
grep -n "ai_assisted" anotae/core/models.py
I-1 — Vault.db cai em mãos erradas
Item
Detalhe
Mitigação
ChaCha20-Poly1305 + Argon2id (DEFAULT m=64MiB t=3 p=1)
Onde verificar
anotae/persistence/crypto.py:DEFAULT_TIME_COST (=3) e DEFAULT_MEMORY_COST (=65536)
Comando auditor
python -m anotae kdf benchmark --target 0.5 (verifica no hardware do auditor)
I-2 — Logs/stack traces expõem PII
Item
Detalhe
Mitigação
friendly_error_text() redige paths com username (PR #22)
Onde verificar
anotae/core/error_messages.py:redact_home_paths
Comando auditor
pytest tests/unit/test_error_messages.py -k redact
I-3 — Backup contém PII em texto claro
Item
Detalhe
Mitigação
Backups são cópias byte-a-byte do vault cifrado
Onde verificar
anotae/persistence/backup.py:create_backup (usa shutil.copy2)
Comando auditor
bash scripts/smoke-e2e.py --keep + file dist/.../backups/*.db (verificar magic bytes SQLite cifrado)
I-4 — Telemetria local expõe PII
Item
Detalhe
Mitigação
Whitelist de 29 eventos categóricos; valores em extra ≤64 chars + escalar; default OFF
Onde verificar
anotae/core/telemetry.py:ALLOWED_EVENTS + _validate_extra
Comando auditor
pytest tests/unit/test_telemetry.py -k pii
I-5 — Memory dump expõe master key
Item
Detalhe
Mitigação
_secure_zero_bytes zera master key após derivar (best-effort)
Onde verificar
anotae/persistence/crypto.py:_zero_master
Comando auditor
grep -n "_zero_master\|secure_zero" anotae/persistence/
Limitação
Python não controla GC — best-effort. Documentar para usuário não rodar em sessão suspeita
I-6 — Side channel timing em verificação de senha
Item
Detalhe
Mitigação
hmac.compare_digest ao verificar token; Argon2id é constant-time
Onde verificar
anotae/persistence/vault.py:_verify_password
Comando auditor
grep -n "compare_digest\|compare_bytes" anotae/persistence/vault.py
I-7 — Anonimização inadequada em export
Item
Detalhe
Mitigação
3 níveis (none/weak/strong) com salt aleatório; k-anonymity opcional (PR #51)
Onde verificar
anotae/core/anonymizer.py (anonymize_encounter, apply_k_anonymity)
Comando auditor
pytest tests/unit/test_anonymizer.py tests/unit/test_k_anonymity.py
I-8 — Strings traduzíveis (.pot) expõem PII
Item
Detalhe
Mitigação
xgettext só pega literais; runtime nunca entra
Onde verificar
scripts/i18n-extract.sh + locale/anotae.pot
Comando auditor
grep -i "cns\|cpf\|paciente" locale/anotae.pot (esperado: zero ou só chaves de UI)
D-1 — Argon2id trava hardware modesto
Item
Detalhe
Mitigação
Detecção automática de RAM em detect_kdf_params() cai para FALLBACK em <4GB
Onde verificar
anotae/persistence/crypto.py:detect_kdf_params
Comando auditor
pytest tests/unit/test_crypto.py -k kdf_params
D-3 — OOM via payload absurdo
Item
Detalhe
Mitigação
Validação de tamanho em nmh/protocol.py; HTTP loopback rejeita >1MB
Onde verificar
anotae/nmh/protocol.py:MAX_MESSAGE_SIZE + anotae/http_bridge/server.py
Comando auditor
grep -n "MAX_MESSAGE_SIZE\|max_size" anotae/nmh/ anotae/http_bridge/
D-5 — Atacante força fallback Argon2id
Item
Detalhe
Mitigação
Parâmetros KDF gravados em vault_meta no momento da criação — não negociáveis em open
Onde verificar
anotae/persistence/vault.py:_load_vault_meta
Comando auditor
pytest tests/integration/test_vault.py -k kdf_params
E-1 — Plugin de mapping malicioso
Item
Detalhe
Mitigação
Plugins são apenas dados JSON; sem eval (PR #35)
Onde verificar
anotae/core/mapping_plugin.py + anotae/core/mapping_engine.py
Comando auditor
grep -n "eval\|exec\|subprocess" anotae/core/mapping_*.py (esperado: zero matches)
Item
Detalhe
Mitigação
Whitelist de variáveis; string.Template ou regex próprio (não Jinja2)
Onde verificar
anotae/core/template_renderer.py:ALLOWED_VARS
Comando auditor
grep -n "Jinja\|eval" anotae/core/template_renderer.py (esperado: zero)
E-3 — Extensão escala privilégios ao app
Item
Detalhe
Mitigação
NMH whitelist de mensagens em protocol.py
Onde verificar
anotae/nmh/protocol.py:MessageType enum
Comando auditor
grep -n "MessageType" anotae/nmh/protocol.py
E-4 — Subprocess vaza arg injection
Item
Detalhe
Mitigação
Argumentos hardcoded com subprocess.run([list, ...]); sem shell=True
Onde verificar
Toda chamada a subprocess no codebase
Comando auditor
grep -rn "shell=True" anotae/ scripts/ (esperado: zero)
LINDDUN
L-1 — Encounter linkado a paciente em export anonimizado
Item
Detalhe
Mitigação
Hash com salt aleatório por export; IDs ANON-XXXXXXXX não reutilizáveis cross-export. Suite anti-rainbow (PR #66) garante 10 propriedades.
Onde verificar
anotae/core/anonymizer.py:_hash_truncate + tests/security/test_anonymizer_anti_rainbow.py
Comando auditor
pytest tests/security/test_anonymizer_anti_rainbow.py -v
Id-1 — Vault descriptografado revela identidade real
Item
Detalhe
Mitigação
Senha-mestra obrigatória
Onde verificar
anotae/persistence/vault.py:open_vault
Comando auditor
Tentar abrir vault sem senha — esperar SecurityError
Id-3 — Texto SOAP em audit details revela identidade
Item
Detalhe
Mitigação
Audit details são metadados estruturados, não texto livre
Onde verificar
anotae/persistence/audit_log_repository.py:_validate_extra
Comando auditor
pytest tests/integration/test_audit_log_repository.py -k pii
N-1, N-2 — Non-repudiation aceita
Aceitas por design (CFM exige rastreabilidade; Sigstore Rekor é log público).
D-2 — Tráfego de rede revela uso
Item
Detalhe
Mitigação
Sem rede — NMH stdin/stdout; HTTP loopback nunca sai de 127.0.0.1
Onde verificar
anotae/http_bridge/server.py (binding)
Comando auditor
grep -n "bind\|0\\.0\\.0\\.0\|address" anotae/http_bridge/server.py
U-1 — Usuário não sabe que telemetria local existe
Item
Detalhe
Mitigação
Default OFF; aba 'Privacidade' no AboutDialog informa explicitamente
Onde verificar
anotae/ui/views/about_dialog.py:_tab_privacy
Comando auditor
Abrir Anotae, ir em Ajuda → Sobre → aba Privacidade
U-2 — Usuário não sabe que audit log existe
Item
Detalhe
Mitigação
Vault → Histórico (Ctrl+H) expõe interface; schema docs em docs/reference/schema.md
Onde verificar
anotae/ui/views/audit_history_dialog.py
Comando auditor
Abrir Anotae, Ctrl+H
U-3 — Usuário não sabe quais dados saem ao exportar
Item
Detalhe
Mitigação
Aviso amarelo no ExportEncounterDialog + 3 níveis explícitos
Onde verificar
anotae/ui/views/export_encounter_dialog.py (warning label)
Comando auditor
Abrir Anotae, exportar atendimento atual, observar UI
Nc-1 — LGPD Art. 12 anonimização inadequada
Item
Detalhe
Mitigação
3 níveis explícitos + k-anonymity; testes invariantes
Onde verificar
anotae/core/anonymizer.py + tests/unit/test_anonymizer.py + tests/unit/test_k_anonymity.py
Comando auditor
pytest tests/unit/test_anonymizer.py tests/unit/test_k_anonymity.py -v
Nc-3 — CFM 2.454/2026 — uso de IA exige registro
Item
Detalhe
Mitigação
Disclaimer fixo no editor; metadata.ai_assisted; sei_inject_dialog reforça humano-no-loop
Onde verificar
anotae/core/models.py:EncounterMetadata.ai_assisted
Comando auditor
grep -n "ai_assisted" anotae/core/models.py anotae/ui/views/
Nc-5 — AGPL §6 acesso ao código-fonte
Item
Detalhe
Mitigação
AboutDialog → Licença AGPL-3.0 com texto integral + link GitHub. Sigstore prova proveniência
Onde verificar
anotae/ui/views/about_dialog.py:_tab_license
Comando auditor
Abrir Anotae, Ajuda → Sobre → aba Licença AGPL-3.0
Resumo de cobertura
Categoria
Total ameaças
Com evidência neste checklist
%
STRIDE
30
28
93%
LINDDUN
13
13
100%
Total
43
41
95%
Ameaças com evidência indireta (não listadas detalhadamente aqui mas
cobertas pelo THREAT-MODEL):
- T-2 (MITM NMH) — coberto por design
- D-2 (vault grande) — limitação aceita pelo usuário
Como rodar a auditoria local
Auditor pode reproduzir esta tabela executando os comandos da
coluna "Comando auditor". Sugestão de fluxo:
# 1. Setup
git clone https://github.com/carlosefdeavila/anotae.git
cd anotae
bash scripts/maintainer-onboard.sh # ~5 min, cria .venv-maint/
# 2. Testes específicos por categoria
source .venv-maint/bin/activate
pytest tests/security/ # invariantes de cripto
pytest tests/unit/test_anonymizer.py # I-7, Nc-1
pytest tests/unit/test_k_anonymity.py # I-7
pytest tests/unit/test_telemetry.py # I-4
pytest tests/integration/test_audit_log_repository.py # R-1, T-5
# 3. Smoke E2E completo
python scripts/smoke-e2e.py
# 4. Verificar reprodutibilidade do build
bash scripts/verify-reproducible.sh # ~3 min em laptop moderno
# 5. SBOM
bash scripts/generate-sbom.sh
jq '.components | length' dist/sbom.json # ~96 componentes
# 6. Verificar Sigstore de release oficial
sigstore verify github \
--repository carlosefdeavila/anotae \
--bundle <bundle.sigstore.json> \
<Anotae-windows-x64.zip>
Quando atualizar este checklist
Sempre que THREAT-MODEL.md ganhar novo item.
Sempre que mitigação migrar de arquivo (refactoring).
Após auditoria externa, atualizar tabela "Status agregado da
auditoria" abaixo + adicionar subseção "Resultado da auditoria
— \<DATA>" com narrativa.
Status agregado da auditoria
Esta tabela é preenchida pelo auditor externo após verificação
ponto-a-ponto das mitigações. Default — (não auditado).
Símbolos: ✅ verificado · ⚠ gap parcial · ❌ falha · 🔄 refinamento sugerido
STRIDE
ID
Categoria
Ameaça
Status
S-1
Spoofing
Usuário malicioso assume identidade do operador
—
S-2
Spoofing
Extensão maliciosa se passa pela Anotae no NMH
—
S-3
Spoofing
App falso responde no HTTP loopback
—
S-4
Spoofing
Site malicioso assume identidade do e-SUS/SISREG/SEI
—
T-1
Tampering
Adulteração do vault.db em disco
—
T-2
Tampering
MITM em mensagens NMH
—
T-3
Tampering
Adulteração de release binário
—
T-3b
Tampering
Adulteração não detectada por chave comprometida
—
T-4
Tampering
Adulteração de dependência via supply chain
—
T-5
Tampering
Audit log adulterado por atacante com SQLite raw
—
T-6
Tampering
Hash do encounter não verificado ao ler
—
R-1
Repudiation
Profissional nega ter editado encounter
—
R-2
Repudiation
Atacante apaga audit log para esconder rastro
—
R-3
Repudiation
Profissional nega uso de IA na geração
—
I-1
Disclosure
Vault.db cai em mãos erradas
—
I-2
Disclosure
Logs/stack traces expõem PII
—
I-3
Disclosure
Backup contém PII em texto claro
—
I-4
Disclosure
Telemetria local expõe PII
—
I-5
Disclosure
Memory dump expõe master key
—
I-6
Disclosure
Side channel timing em verificação de senha
—
I-7
Disclosure
Anonimização inadequada em export
—
I-8
Disclosure
Strings traduzíveis (.pot) expõem PII
—
D-1
DoS
Argon2id trava hardware modesto
—
D-3
DoS
OOM via payload absurdo
—
D-5
DoS
Atacante força fallback Argon2id
—
E-1
Elevation
Plugin de mapping malicioso
—
E-2
Elevation
Template renderer com expressão maliciosa
—
E-3
Elevation
Extensão escala privilégios ao app
—
E-4
Elevation
Subprocess vaza arg injection
—
LINDDUN
ID
Categoria
Ameaça
Status
L-1
Linkability
Encounter linkado a paciente em export anonimizado
—
Id-1
Identifiability
Vault descriptografado revela identidade real
—
Id-3
Identifiability
Texto SOAP em audit details revela identidade
—
N-1, N-2
Non-repudiation
Aceitas por design
—
D-2
Detectability
Tráfego de rede revela uso
—
U-1
Unawareness
Usuário não sabe que telemetria local existe
—
U-2
Unawareness
Usuário não sabe que audit log existe
—
U-3
Unawareness
Usuário não sabe quais dados saem ao exportar
—
Nc-1
Non-compliance
LGPD Art. 12 anonimização inadequada
—
Nc-3
Non-compliance
CFM 2.454/2026 — uso de IA exige registro
—
Nc-5
Non-compliance
AGPL §6 acesso ao código-fonte
—
Resultado da auditoria
Auditoria —
Aguardando auditoria. Esta seção é preenchida pelo auditor com
narrativa por categoria de status.
Itens ✅ (verificados): N de M ameaças
Itens ⚠ (gaps parciais): lista
Itens ❌ (falhas): lista — prioridade alta para fix
Itens 🔄 (refinamentos sugeridos): lista — issues abertos
Recomendações gerais: texto livre do auditor