Plan ejecutable · Vault migration · 7 días sin downtime
FASE 1-2 ejecutadas y verificadas contra estado real · FASE 3-5 checklist con comandos exactos + rollback
FASE 1 · Validación de hallazgos (ejecutada)
F-02
Keypair Solana hardcoded en bridge.mjs grep -n 'KEYPAIR' /srv/cuandeoro_bridge/bridge.mjs →
Línea 10: const KEYPAIR_PATH = '/home/administrator/.velocityquant_secrets/dallas_hot_keypair.json';
Líneas 16-17: fs.readFileSync(KEYPAIR_PATH) → Keypair.fromSecretKey(...)
Archivo existe (227 bytes, mode 600, owner administrator).
Verificado
F-03
Seed BIP-39 deployer en TOML grep -n 'TOML\|seed' /srv/cuandeoro_bridge/finish.mjs →
Línea 11: const TOML_PATH = '/home/administrator/.velocityquant_secrets/cuandeoro_deployer_mainnet.toml';
Líneas 25-28: lee TOML, regex seed_phrase = "...", deriva con StellarHDWallet.fromMnemonic().
Mismo patrón en open_trustline.mjs:7. Archivo TOML existe (179 bytes, mode 600).
Además: cat .velocityquant_secrets/cuandeoro_deployer_mainnet.toml revela seed plaintext "dragon burden enemy skin...".
Verificado
F-08
Soroban admin sin time-lock/multisig grep -n 'upgrade\|update_current_contract_wasm' /srv/cuandeoro_soroban/contracts/cuandeoro-atomic/src/lib.rs → 0 matches.
El contrato NO tiene función upgrade, NO usa env.deployer().update_current_contract_wasm(), NO tiene set_admin.
Admin solo puede: bloquear países (RTO-1), marcar notarial verification, NO puede reemplazar el contrato.
Línea 100 comenta: "multisig Cuandeoro (Marco + Fran + abogado)" — el admin Address SE ESPERA sea un contrato multisig externo (Soroban admite Address ser contrato). El riesgo descrito por el modelo ("upgrade malicioso instantáneo") NO APLICA porque no hay upgrade function. El riesgo residual es: si admin key se compromete, atacante puede bloquear países o marcar notarial — operacional, no drenaje.
Falso positivo
F-09
KYC sin audit log de lecturas cat /srv/cuandeoro_kyc/schema.sql →
Tabla kyc_audit_log EXISTE (líneas 71-83) pero solo registra operaciones: 'create', 'update', 'revoke', 'rotate_dek', 'gdpr_purge'.
NO existe trigger AFTER SELECT, NO existe wrapper de lectura, NO se hace REVOKE SELECT sobre kyc_records.
Atacante con grant SELECT puede ejecutar SELECT * FROM kyc_records y exfiltrar PII cifrado sin rastro en audit log.
Verificado
F-10
gdpr_purge_kyc_record editable cat /srv/cuandeoro_kyc/schema.sql →
Función definida línea 102 con CREATE OR REPLACE FUNCTION ... LANGUAGE plpgsql; NO declara SECURITY DEFINER → ejecuta con permisos del invocador (SECURITY INVOKER por defecto).
NO hay REVOKE ni GRANT EXECUTE explícito en el schema → cualquier role con CREATE FUNCTION puede ejecutar CREATE OR REPLACE y modificarla.
El INSERT al audit log es eliminable modificando la función.
Verificado
Resultado FASE 1: 4/5 VERIFICADOS · 1/5 FALSO POSITIVO (F-08). El plan se enfoca solo en los 4 verificados + secretos descubiertos en FASE 2.
FASE 2 · Inventario de secretos (ejecutado)
Secreto
Ubicación
Usado por
Riesgo
Vault
dallas_hot_keypair.json
~/.velocityquant_secrets/
cuandeoro_bridge/bridge.mjs:10
HOT wallet Solana operativo · 2.2 SOL + 302 USDC
SÍ
cuandeoro_deployer_mainnet.toml
~/.velocityquant_secrets/
finish.mjs:11 + open_trustline.mjs:7
Seed BIP-39 Stellar deployer · control wallet GBL4...HVVA
Vault HashiCorp comprobado: VAULT_ADDR=http://127.0.0.1:8200 vault status → Initialized=true, Sealed=false, Shamir 5/3, Storage=raft, HA active. Listo para alojar la estructura nueva.
FASE 3 · Estructura Vault (comandos ejecutar como root)
Requisito: necesitas VAULT_TOKEN con permisos sys/mounts y sys/policies. Si tienes root token de la ceremonia, úsalo aquí (temporal, no exportar a env permanente).
Rollback: vault secrets disable cuandeoro (los datos quedan en raft hasta GC, pero quedan inaccesibles via mount).
3.2 · Crear estructura jerárquica (paths vacíos)
vault kv put cuandeoro/stellar/deployer placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_1 placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_2 placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_3 placeholder=init
vault kv put cuandeoro/solana/dallas_hot placeholder=init
vault kv put cuandeoro/solana/r211_burnin placeholder=init
vault kv put cuandeoro/smtp/cuandeoro_ie placeholder=init
vault kv put cuandeoro/cloudflare/api_token placeholder=init
vault kv put cuandeoro/postgres/kyc_app placeholder=init
vault kv put cuandeoro/postgres/kyc_auditor placeholder=init
vault kv put cuandeoro/services/archivos_pass placeholder=init
vault kv put cuandeoro/services/audit_dashboard_hmac placeholder=init
vault kv put cuandeoro/services/coinglass_api placeholder=init
vault kv put cuandeoro/services/pumpdump_api placeholder=init
3.3 · Políticas mínimo privilegio (lectura solo, por servicio)
# Política bridge: solo lee dallas_hot + deployer
cat <<EOF | vault policy write cuandeoro-bridge -
path "cuandeoro/data/solana/dallas_hot" { capabilities = ["read"] }
path "cuandeoro/data/stellar/deployer" { capabilities = ["read"] }
path "cuandeoro/metadata/solana/dallas_hot" { capabilities = ["read"] }
path "cuandeoro/metadata/stellar/deployer" { capabilities = ["read"] }
EOF
# Política archivos: solo password propio
cat <<EOF | vault policy write cuandeoro-archivos -
path "cuandeoro/data/services/archivos_pass" { capabilities = ["read"] }
EOF
# Política kyc-app: lee credencial app + función SECURITY DEFINER hace el log
cat <<EOF | vault policy write cuandeoro-kyc-app -
path "cuandeoro/data/postgres/kyc_app" { capabilities = ["read"] }
EOF
# Política admin (solo Marco) - lectura total
cat <<EOF | vault policy write cuandeoro-admin -
path "cuandeoro/*" { capabilities = ["create","read","update","delete","list"] }
EOF
vault policy list | grep cuandeoro
FASE 4 · Migración segura (POR SECRETO con rollback)
Regla absoluta: en ningún caso eliminar el archivo plaintext hasta haber validado el servicio leyendo desde Vault y mantenerlo funcionando >1h sin errores. shred solo en FASE 5.
S-01 · ARCHIVOS_PASS (más simple, hacer primero para validar pipeline)
Rollback S-02: cp /srv/cuandeoro_bridge/bridge.mjs.bak-XXX /srv/cuandeoro_bridge/bridge.mjs. El archivo plaintext sigue intacto (Vault es copia adicional, no reemplazo aún).
S-06 · audit_dashboard_shared_secret + 2 API keys (coinglass, pumpdump)
FASE 5 · Retirada controlada (solo si todo FASE 4 OK >48h)
Pre-requisito: 48 horas sin errores en logs · bridge.mjs ejecutó al menos 1 tx real desde Vault · archivos_cuandeoro ha tenido al menos 1 login con la nueva password. Si NO se cumple → NO ejecutar FASE 5.
Rollback FASE 5 si algo falla: sudo tar -xzf /sda-disk/cuandeoro_secrets_pre_purge_*.tgz -C / restaura todos los plaintext. La tarball NUNCA se borra.
Resumen estado de hallazgos no cubiertos por este plan
Sesión SQL separada · ALTER OWNER + REVOKE ALTER + SECURITY DEFINER
Resumen final del plan: 4 hallazgos verificados → 6 migraciones de secretos (S-01 a S-06) → retirada en FASE 5. Tiempo estimado 7 días si haces 1 migración/día con validación 24h cada una. Cada paso es reversible hasta FASE 5. F-09 y F-10 son SQL puro y los abordamos en sesión separada con qwen-coder.