Ir para o conteúdo

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

  1. Cloning + setup:

    git clone https://github.com/carlosefdeavila/anotae.git
    cd anotae
    bash scripts/maintainer-onboard.sh   # ~5 min
    

  2. Para cada linha: rodar o "Comando auditor" da tabela e verificar a evidência. Adicionar coluna "Status" preenchida com símbolo apropriado.

  3. 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

T-5 — Audit log adulterado por atacante com SQLite raw

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)

E-2 — Template renderer com expressão maliciosa

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