Alcancía guarda tus finanzas en tu computador, así que un error de seguridad puede importar mucho. Si encontraste uno, gracias por avisarnos en privado. (English below.)
- Entra a Reportar una vulnerabilidad (pestaña Security del repo → Report a vulnerability). Solo lo ve quien mantiene el proyecto.
- Cuenta qué pasa, cómo repetirlo y qué podría hacer alguien con eso. Si necesitas un archivo de ejemplo, arma uno ficticio: nunca mandes una cartola real, llaves de un servicio ni datos tuyos.
- No abras un issue público ni lo cuentes en Discussions hasta que esté arreglado.
- Te respondemos en 5 días hábiles como máximo (es un proyecto chico, mantenido por personas).
- En 30 días te contamos qué vamos a hacer y, si se puede, ya está arreglado. Lo grave va primero.
- Publicamos el aviso de seguridad cuando haya versión arreglada, con tu nombre si quieres. Si después de 90 días no hay arreglo, conversamos cómo hacerlo público.
- Si investigas de buena fe, sin tocar datos de otras personas ni dañar nada, no vamos a tomar ninguna acción en tu contra.
Todo lo de este repo y lo que sale de él: la app de Mac (y las de Windows y Linux cuando existan), la app del celular (movil/,
iPhone y Android), los scripts de bin/, la interfaz de ui/, la copia cifrada para el celular, los conectores, el servidor MCP,
las actualizaciones, la página publicada y los workflows de GitHub. También el
catálogo de recetas.
Nos interesa especialmente:
- Que una cartola, una receta, una traducción, la descripción de un movimiento o la respuesta de una IA logre ejecutar código, leer archivos o usar el puente con la app.
- Que una llave de un conector salga del Llavero hacia otro lugar que no sea el dominio oficial del servicio.
- Que alguien pueda hacer llegar una actualización falsa de Alcancía.
- Que la IA de la persona vea más de lo que dice el README (nunca números de cuenta, RUT ni claves).
- Que la copia para el celular se pueda abrir sin la frase, cambiar sin que se note, o lleve algo que no debería (llaves, tokens, rutas del computador): el formato está en el README.
- Que un pull request pueda robar secretos o permisos de los workflows.
No cubre: lo que exige tener ya el control de tu computador o de tu cuenta de usuario, problemas de la IA que tú elegiste (Claude, ChatGPT/Codex o Gemini) o de los servicios con los que conectas, ni ataques de ingeniería social.
- Sin servidores propios ni telemetría; tus datos viven en
~/Alcancia, solo para tu usuario. - Nunca pedimos la clave del banco. Las llaves de los conectores van al Llavero, viajan por la entrada estándar y solo a los dominios declarados de cada servicio, sin seguir redirecciones.
- Recetas = solo datos, validadas. Todo lo que viene de afuera se escapa antes de mostrarse y la interfaz tiene una política de contenido (CSP) que no deja correr código que no venga con la app.
- La IA corre en una carpeta temporal, sin herramientas ni conexiones extra, y lo que propone se valida y la persona lo confirma.
- Al celular los datos llegan cifrados (PBKDF2-SHA256 de 600.000 vueltas + AES-256-GCM, IV nuevo en cada escritura) en la nube de la persona; la frase no se guarda en ninguna parte (el Mac guarda la llave derivada en su Llavero, el celular solo si la persona lo pide, en el Llavero o el Keystore). La app del celular no tiene permiso de internet, ni respaldo automático en Android, ni excepciones de ATS en iOS.
- La app de Mac es la pieza «host-tauri» de Pieza (
escritorio/src/pieza, Rust + Tauri): el puente solo atiende la ventana propia con su página enui/y la ventana nunca navega fuera; lo que pide la interfaz se valida contraacciones.jsonantes de correr nada: lo que va como argumento es solo un valor de una lista cerrada o algo ya revisado (el id de un conector, una receta, el país), lo demás va en un archivo de entrada en una carpeta temporal 0700 y el script lo vuelve a revisar, y una ruta absoluta solo vale si es la cartola que la persona eligió en el diálogo del sistema. Cada script tiene límite de tiempo (se corta también lo que lanzó, y al salir no queda nada corriendo) y corre sin variablesALCANCIA_*de afuera. Las llaves van al llavero del sistema (Secretos, solo en ese Mac) y llegan al script solo por la entrada estándar. - Todo cambio entra por pull request revisado. Las actions de GitHub están fijadas por SHA, con permisos mínimos y sin
pull_request_target. - Actualizaciones (pieza «actualizaciones»): solo de
https://github.com/alcancia-app/alcancia/releases/download/…, la redirección de GitHub solo por https y hoy se verifica la huella SHA-256 publicada junto al Release; nunca con un guardado o un script corriendo. La firma de las actualizaciones (para que ni siquiera alguien con acceso a la cuenta de GitHub pueda publicar una versión falsa) está diseñada y pendiente: ver abajo.
Estado hoy: todavía no hay Releases publicados. Cuando los haya, la app baja Alcancia-macOS.zip y su .sha256 del mismo
Release: eso detecta una descarga rota, pero no una versión falsa subida por alguien que tome la cuenta de GitHub (subiría las dos
cosas). La app va firmada ad hoc y el actualizador le quita la cuarentena, así que macOS tampoco la revisa.
Lo que se propone, antes del primer Release:
- Una llave Ed25519 que se crea una sola vez en el Mac de quien mantiene el proyecto (CryptoKit
Curve25519.Signing), con la privada en el Llavero (no sincronizada, ojalá con confirmación) y un respaldo fuera de línea. Nunca en GitHub ni en un secreto de Actions: si la cuenta cae, la llave no cae con ella. - La pública se escribe en la app (en la pieza «actualizaciones» de Pieza,
escritorio/src/pieza/actualizaciones.rs, que se configura con una constante en base64 de Alcancía: el cambio va primero a Pieza). Se puede tener una segunda pública de reserva para poder rotar si la primera se pierde. - Al publicar,
herramientas/empaquetar.sh(en el Mac) firma el SHA-256 del zip junto con la versión (alcancia-actualizacion|<versión>|<sha256>) y dejaAlcancia-macOS.zip.sig(base64) para subir al Release. - La app baja zip,
.sha256y.sigcon URLSession, calcula el SHA-256, verifica la firma conCurve25519.Signing.PublicKey.isValidSignaturey revisa que la versión firmada sea la del Release y mayor que la instalada (así no se puede volver a una versión vieja con fallas). Solo si todo calza escribe el guion que reemplaza la app. Sin.sigválido: no actualiza y lo dice. - Alternativa (o complemento) con costo: firmar con Developer ID de Apple y notarizar; el guion verificaría con
codesign --verify --deep --strict -R '=anchor apple generic and certificate leaf[subject.OU] = "<TEAMID>"'y ya no haría falta quitar la cuarentena a ciegas.
Por qué no está implementado todavía: cambia el camino de instalación de la app, que no se puede compilar ni probar fuera de un Mac, y un actualizador roto no se puede arreglar con otra actualización. Se hace junto con el primer Release, probándolo en el Mac.
Report privately through Report a vulnerability (GitHub's private vulnerability reporting). Don't open a public issue. Never send real bank statements, API keys or personal data: build a fictitious sample instead.
We reply within 5 business days, share a plan within 30 days, and publish an advisory once a fix ships (crediting you if you wish); after 90 days without a fix we'll agree on disclosure with you. Good-faith research that doesn't touch other people's data is welcome and won't be pursued.
The Mac app is Pieza's generic «host-tauri» piece (Rust + Tauri): only the app's own window with its page in ui/ can use the bridge, every request is
validated against acciones.json before anything runs (arguments are only values from a closed list or already-checked ids; the
rest goes in an input file and the script checks it again; an absolute path is only accepted if it's the statement you picked), every script has a
time limit, and keys live in the Keychain and reach scripts only through standard input. Updates come only from this repo's
Releases, with their SHA-256 checked.
In scope: the Mac app (and future Windows/Linux apps), the phone app (movil/) and its encrypted copy, bin/ scripts, the ui/ interface, connectors, the MCP server, updates,
the published site, GitHub workflows, and the recipe catalog. We especially care about code execution from statements, recipes,
translations, transaction descriptions or AI replies; connector keys leaving the Keychain for anything but the service's official
domain; forged updates; the AI seeing more than documented; and pull requests stealing workflow secrets or permissions.
Out of scope: attacks that already require control of your computer or user account, issues in the AI tool or connected service
themselves, and social engineering.