11 KiB
07. Findings tracker — известные ограничения
Открытый реестр всех известных уязвимостей, дефектов и архитектурных gap. Severity по шкале:
- блокер mainnet — запуск в production невозможен до закрытия
- высокий — производственный риск, обязательно закрыть до публичного релиза
- средний — допустимо запустить с явным acknowledgment
- низкий — косметика, document-hygiene
Все findings имеют closure path — конкретные шаги для устранения.
Закрыто в v6.5.0 (Phase 1)
CF-1 — Swallowed catch без логирования ✅
Класс: error surface (Pass 7).
Severity: средний.
Closure: commit cf1 (v6.5.0). 10/13 catch теперь логируют Log.w(TAG, ...). Остаётся 3 в Thread.sleep (interrupt handling, acceptable per Kotlin pattern).
CF-2 — Regex JSON parser ✅
Класс: parser robustness (Pass 8/10).
Severity: средний.
Closure: commit cf2 (v6.5.0). Заменён на org.json.JSONObject с optDouble/optString/optBoolean и fail-safe NaN-проверкой.
CF-3 — BIP39 wordlist integrity check ✅
Класс: integrity / supply chain (Pass 0 [C-9]).
Severity: блокер mainnet до закрытия.
Closure: commit cf3 (v6.5.0). Hardcoded SHA-256 2f5eed53...dbda в MainActivity.bip39(). Fail-closed: возвращает пустую строку → JS бросает «bip39 list size: 0» → создание кошелька невозможно.
CF-5 — balances.json race condition ✅
Класс: concurrency (Pass 8).
Severity: средний.
Closure: commit cf5 (v6.5.0). Atomic with_state_lock() через отдельный .lock файл с единым LOCK_EX на read+modify+write.
CF-7 — silent JSON swallow на backend ✅
Класс: error surface (Pass 7).
Severity: низкий.
Closure: commit cf7 (v6.5.0). force=True + явный 400 invalid json с detail.
F-1 — Stale assigned_node поле ✅
Класс: consistency drift (Pass 13).
Severity: низкий.
Closure: commit f1 (v6.5.0). Удалены assigned_node/assigned_ts поля из всех записей balances.json.
F-3 (частично) — anon-bloat в balances.json ✅
Класс: state lifecycle (Pass 18 / [I-14]).
Severity: средний.
Partial closure: commit f3 (v6.5.0). /api/vpn/admin/purge endpoint удаляет inactive 30+ days с balance=0. Manual trigger.
Остаётся open: automated daily cron (см. ниже F-3.1).
Открытые findings
F-2 — Heartbeat без cryptographic authentication ⛔
Класс: authentication / Sybil (Pass 19, Pass 22). Severity: блокер mainnet.
Поверхность: POST /api/vpn/heartbeat принимает {"address": "<40-hex>"} и проверяет только request.remote_addr ∈ MONTANA_NODES. Никакой подписи владельца адреса не требуется.
Атака:
- Атакующий поднимает Montana VPN клиент (открытый VLESS link).
- Генерирует 10⁶ случайных 40-hex адресов.
- Шлёт 10⁶ heartbeat каждые 5 секунд через VPN.
- Backend начисляет 0.001 × 5 × 10⁶ = 5000 Ɉ/период на fake-адреса.
Defense сейчас: нет.
Closure path:
- Phase 3 (M-VPN-3): Falcon-512 keypair generation в Android — каждый кошелёк имеет
(pubkey, secretkey)от seed. - Heartbeat body расширяется:
{address, window_index, exit_node, signature}где signature — Falcon-512 над(address || window_index || exit_node). - Backend хранит pubkey per address (заполняется при первом heartbeat) → проверяет signature над всеми последующими.
- Atomic operation: верификация подписи → начисление credit.
Cost estimate: 2 недели (JNI bridge для pqcrypto-falcon + key derivation от BIP39 seed + backend signature verify).
F-4 — balances.json НЕ реплицируется на узлы Montana ⛔
Класс: persistence / SPOF. Severity: блокер mainnet.
Поверхность: balance state живёт только в /var/lib/montana-vpn-balance/balances.json на Moscow. Если Moscow упадёт безвозвратно (диск, hosting termination, государственный захват) — все начисленные Ɉ потеряны.
Что я ошибочно заявлял раньше: «всё сохраняется на узлах через montana-orchestrator.service». Неверно — orchestrator занимается регистрацией узлов, не балансами.
Closure path:
- Phase 2 (M-VPN-1): реплицировать balances.json на Helsinki + Frankfurt + NewYork через
rsyncdaily. Mitigation, не fix. - Phase 3 (M-VPN-2): интегрировать с TimeChain — heartbeat становится подписанной операцией
0x06 VpnHeartbeat→ попадает в proposal → cemented через консенсус → AccountTable обновляется на ВСЕХ узлах. Authoritative persistence.
Cost estimate: Phase 2 — 3 дня. Phase 3 — 2 недели (новый opcode в спеке + mt-account изменения + montana-node integration).
F-6 — Seed в plain text без шифрования
Класс: privacy at rest (Pass 19). Severity: высокий (на rooted устройствах).
Поверхность: localStorage.setItem("m.seed", "ranch basket resource ...") в WebView Local Storage leveldb.
Атаки:
- Root доступ к
/data/data/quest.montana.vpn/app_webview/Default/Local Storage/leveldb/→ читает плоский текст - Forensic image устройства → offline analysis
- Backup через ADB → seed в backup
Closure path:
- User passcode + PBKDF2(passcode → AES key) → wrap seed AES-GCM
- Или Android Keystore (hardware-backed) для wrap
Cost estimate: 1 неделя (UX flow + crypto + миграция existing wallets).
F-7 — Backup confirmation отсутствует
Класс: UX-as-security. Severity: высокий (вероятная потеря денег пользователями).
Поверхность: см. 06-Восстановление.md §6.
Closure path: новый экран s-backup-verify между s-auth и s-main при создании.
Cost estimate: 1 день.
F-8 — BIP44 несовместимость для cross-wallet import
Класс: narrative-model divergence. Severity: средний (UX).
Поверхность: см. 06-Восстановление.md §5. 24 слова Montana → импорт в Trust/MetaMask показывает пустые балансы.
Closure path (выбор):
- A. Добавить UI warning при показе seed
- B. Apply for SLIP-44 coin type + переход на BIP44 derivation path → cross-wallet import работает
Option A — 30 минут. Option B — недели (SLIP-44 registration + backward-incompatible breaking change существующих addresses).
CF-4 — Reality keys + UUID в 19 местах ([C-1] SSOT violation)
Класс: SSOT. Severity: средний.
Поверхность: см. 04-Сетевой-слой.md §15.
Closure path: Phase 2 — Rust crate mt-vpn-config-gen читает keys из mt-genesis::ProtocolParams::reality_keys, генерирует все 19 конфигов.
Cost estimate: 3 дня.
CF-6 — https://montana.local/ synthetic baseURL
Класс: production naming [C-12]. Severity: низкий.
Closure: переименовать в https://montana.quest/app/ (синтетический, naружу не идёт). 5 минут.
F-3.1 — Automated purge cron отсутствует
Класс: state lifecycle (Pass 18). Severity: низкий.
Closure: добавить systemd timer montana-vpn-balance-purge.timer daily + автоматический вызов в самом heartbeat (раз в 1000 операций). 1 час.
CF-recovery-tests — Recovery E2E test отсутствует
Класс: Pass 20 user recovery trace. Severity: высокий.
Поверхность: см. 06-Восстановление.md §4. Нет automated test что mnemonic → adr воспроизводимо между устройствами.
Closure path:
- Add
BIP39DerivationTest.ktunit test (JVM) — берёт известный mnemonic, проверяет адрес против hardcoded expected hex - Add
RecoveryE2ETest.ktinstrumented test — то же, но в реальном WebView
Cost estimate: 2 дня.
F-reality-pq — Reality X25519 не пост-квантово
Класс: [I-1] PQ-secure compliance. Severity: низкий (на горизонте 10 лет).
Поверхность: Reality использует X25519 для key exchange — уязвим к квантовому компьютеру (Shor).
Closure path: upstream XTLS реализация PQ-Reality (work in progress, не наша работа). На горизонте 5-10 лет (CRQC threat model).
F-keystore-backup — Genesis keystore без backup procedure
Класс: operational security. Severity: высокий.
Поверхность: /Users/kh./Python/Ничто/Montana/Android/keystore/montana.keystore хранится только на устройстве автора. Компрометация = malicious APK подписи.
Closure path: HSM или Shamir-split keystore на N доверенных лиц с threshold.
Roadmap закрытия
Phase 2 (M-VPN-1, ~1-2 недели) — Rust backend
- Заменить Flask
app.pyна Rustmt-vpn-balance(axum + sqlx + SQLite WAL) - F-4 mitigation: rsync replication на 3 узла Montana
- CF-4 closure:
mt-vpn-config-genбинарь читает Reality keys из единого источника - F-3.1: cron purge
- CF-recovery-tests: unit + instrumented tests
- F-7: backup verify screen
- F-8: UI warning
Phase 3 (M-VPN-2/3, ~3-4 недели) — TimeChain integration
- F-2 + F-4 final closure: новый opcode
0x06 VpnHeartbeatвMontana Protocol v35.26 - mt-account реализация apply_vpn_heartbeat (50+ тестов)
- montana-node accepts heartbeat в mempool → cemented через consensus
- AccountRecord.balance обновляется через canonical apply pipeline
- Android JNI bridge для Falcon-512
- F-6 closure: encrypted seed через user passcode
Phase 4 (опциональная, поздно) — Hardening
- F-reality-pq: переход на PQ-Reality когда XTLS upstream готов
- F-keystore-backup: HSM или Shamir split