Parte IV — Copa, suelo y cuidado

11 · Cuidar el árbol

El baobab viejo tiene un hueco en el tronco, y el hueco también es parte del árbol. Este módulo lista los huecos que encontró la revisión de octubre de 2026 — los que se cerraron y los que quedan como trabajo de la comunidad.

Corregidos en la 3.3

#ProblemaDóndeCómo se cerróPrueba
1Inbox ActivityPub siempre montada, sin firma, con upsert en el uuid elegido por quien envía: cualquiera sobrescribía el saber de un OXALÁ, de la mucua o de la galaxia, y el commit se propagaba en el syncapi/v3/activitypub.py, federacao/ingestao.pyruta solo con BBX_FED_AP=on; HTTP Signature de una mucua conocida (Digest + Date); la ingestión no toca saberes locales, no acepta identidad ni uuid mal formadotest_federacao_inbox_segura.py
2Token EdDSA de otra mucua: cualquier mucua conocida emitía un token con el sub de un OXALÁ local y mucua = local, y obtenía la administración de la instancia; una copia falsificada del saber de la mucua local permitía emitir tokens "locales"services/auth.pyemisor local solo con la clave del disco; una mucua de fuera solo responde por sus propias mocambolas; mucua y username recalculados; IdP externo siempre USERtest_token_federado_recalcula_papel.py
3Descarga de anexos, miniaturas y portada de colección sin control de lectura: acl, privado, borrador y galaxia restringida salían para anónimosservices/saber_service.py, api/v3/saberes.py, colecoes.pycontent_path, thumbnail_path, colecao_mosaico_path reciben actor y pasan por can(READ)test_vazamentos_de_leitura.py
4XSS: [x](javascript:…) en el markdown y URLs de campos del saber se volvían enlaces ejecutablesfront lib/util/markdown.ts y páginashrefSeguro—
5SVG servido inline por la API en el mismo origen del sitio ejecutaba scriptsapi/v3/saberes.pyCSP sandbox + nosniff—
6Sin límite de intentos de contraseña (/auth/login, /auth/token, /xmpp/extauth)services/auth.pyfreno por cuenta (10 errores en 15 min)test_freio_login.py
7git clone <url> con url venida de la API: --upload-pack=… ejecutaría un comandoinfra/sync/*.py-- y rechazo de urls que empiezan con -—
8extauth del XMPP alcanzable desde internetnginxallow 127.0.0.1—

Huecos que quedan (para que la comunidad decida)

  1. El password_hash viaja en el git. Toda galaxia clonada lleva los hashes de todas las cuentas. PBKDF2 con 200 mil rondas retrasa, pero no impide un ataque offline. Camino: sacar la contraseña del saber.bbx (como las claves privadas) o cambiar a Argon2/scrypt, más caros.
  2. Token de 7 días con el rol sellado. Bajar de rol a alguien solo vale en el próximo login. Los grupos ya se resuelven en cada petición — el rol puede seguir el mismo camino, o el token puede durar menos con renovación.
  3. Token en la query string (?access_token=) para <img>/<video>: queda en el log del nginx y en el historial. Camino: token corto solo para medios, o cookie HttpOnly leída por la API.
  4. Token en el localStorage + cookie sin HttpOnly. Cualquier XSS roba la sesión. El hrefSeguro cierra el caso conocido; una CSP en el front cerraría la clase entera.
  5. BBX_CADASTRO_ABERTO=on por defecto en el paquete: en una mucua expuesta a internet, cualquiera crea una cuenta y sube archivos de hasta 4 GB, que se sincronizan hacia la red.
  6. La API escucha en 0.0.0.0:8000 (necesario para la red local y para Tor), con /docs abierto. Considerar BBX_DOCS=off en producción.
  7. Federación AP incompleta: las entregas ya salen firmadas, pero no hay registro de seguidores (seguidores_inbox), y la pubkey de una mucua puede venir de cualquier galaxia instalada. Antes de activar BBX_FED_AP, definir en qué galaxias se confía.
  8. SaberService con 4000 líneas. Dividirlo por tema (lectura, escritura, colecciones, eventos, estructura) facilita la revisión de seguridad.
  9. Front con ~55 errores de tipo (npm run check).
  10. permissions.pode_administrar_instancia devuelve True cuando no consigue leer la identidad local ("comportamiento antiguo"). En producción eso no pasa, pero fallar cerrado sería más seguro.

Ejercicios de fin de curso

  1. Hueco 2: haz que el rol se recalcule en deps._moc_from_token en cada petición (como los grupos), con caché corta. Escribe la prueba antes.
  2. Hueco 6: añade BBX_DOCS=off en api/v3/app.py y en el backend.env del paquete.
  3. Hueco 4: escribe una Content-Security-Policy para SvelteKit (kit.csp en svelte.config.js) y descubre qué se rompe.
  4. Nueva nature: crea la nature cantiga (letra, intérprete, territorio, audio) solo por la API, sin tocar el código. ¿Qué faltó?
  5. Ruta de sneakernet real: arma, con dos máquinas y un pendrive, un pedido que atraviese tres mucuas.

Glosario

TérminoEn el códigoQuiere decir
sabercore/saber.pycualquier cosa guardada; la unidad
naturenatures/el tipo de un saber
mucuainfra/mucua_local.pyuna instancia (el fruto del baobab)
galaxia (galáxia)SaberRepositoryun acervo = un repositorio git
mocambolanature mocambolauna persona
territorio (território)nature territorioel suelo de una mucua
Sankofainfra/sankofa.pyla fachada del git/annex (volver y buscar)
linkservices/links.pyun remote git de una galaxia
ruta (rota)nature rotacamino físico de sneakernet
pedidonature pedido"quiero una copia de este archivo"
lente / aplicaciónapplications/una forma de ver los saberes
OXALÁ, PAJÉ, USERconstants.ROLE_*roles (galaxia, mucua, uno mismo)
gestor localmucua_local.gestores_locaiscoadministrador invitado por esta máquina
procedencia (procedência)data.enriquecimentolo que la máquina hizo con un anexo
faro (farol)infra/farol_lan.pyel anuncio en la red local

Cierre

Un baobab no es de quien lo plantó: es de quien se sienta debajo de él. El código también. Léanlo juntos, discrepen de los comentarios, escriban pruebas para las historias de su comunidad.

ver este capítulo como saber