
Un recolector y servidor de payloads ligero para Blind XSS (Cross-Site Scripting) construido con Flask
Un colector y servidor de payloads Blind XSS (Cross-Site Scripting) ligero construido con Flask. Sirve un payload de JavaScript que captura datos del navegador de la víctima (cookies, localStorage, fragmentos del DOM, etc.) y los reenvía a un panel respaldado por SQLite protegido con HTTP Basic Auth.
/p.js sirve un payload JS autocontenido usando sendBeacon o fetch/c (JSON/FormData) y GET /c.gif (pixel beacon compatible con CSP)/events lista los eventos capturados, /events/<id>/view muestra los detalles completos/payloads ofrece 14 variantes de payloads XSS más un editor JS personalizadoADMIN_USER / ADMIN_PASSWORDbxss.db la reconstruye desde ceroDockerfile y docker-compose.yml# Set credentials
echo "ADMIN_USER=admin" > .env
echo "ADMIN_PASSWORD=your-admin-password" >> .env
# Build and run
docker compose up -d --build
Dashboard: http://127.0.0.1:8089/events (el navegador solicitará autenticación básica)
pip install -r requirements.txt
export ADMIN_USER="admin"
export ADMIN_PASSWORD="your-admin-password"
gunicorn -b 127.0.0.1:8080 --workers 2 --threads 4 wsgi:app
/payloads (tras autenticarte) para copiar un payload XSS./events.| Método | Ruta | Descripción |
|---|---|---|
| GET | /p.js | JavaScript del payload XSS |
| POST | /c | Recibe JSON/FormData del payload |
| GET | /c.gif | Baliza pixel (compatible con CSP) |
| Método | Ruta | Descripción |
|---|---|---|
| GET | /events | Últimos 500 eventos |
| GET | /events/<id> | Detalle del evento en JSON |
| GET | /events/<id>/view | Detalle del evento en HTML |
| GET/POST | /payloads | Generador de payloads + editor de JS personalizado |
| Método | Ruta | Descripción |
|---|---|---|
| GET | /_healthz | Comprobación de estado |
| Variable | Predeterminado | Descripción |
|---|---|---|
ADMIN_USER | admin | Nombre de usuario del panel |
ADMIN_PASSWORD | (obligatorio) | Contraseña del panel — el inicio falla si no se establece |
DB_PATH | ./bxss.db | Ruta de la base de datos SQLite |
PUBLIC_URL | (vacío) | URL base pública para los payloads generados (úsala cuando estés detrás de un túnel/proxy inverso; si no, se usa el host de la petición) |
TRUST_PROXY | (vacío) | Establece 1 para confiar en X-Forwarded-For/CF-Connecting-IP para la IP del cliente (solo cuando estés detrás de un proxy inverso de confianza; es necesario ahí o todos los clientes compartirán la IP del proxy para el límite de peticiones) |
MAX_BODY | 524288 | Tamaño máximo del cuerpo del colector (bytes) |
RATE_LIMIT_COUNT | 60 | Máximo de peticiones al colector por ventana (por IP) |
RATE_LIMIT_WINDOW | 60 | Ventana del límite de peticiones en segundos |
LOG_LEVEL | INFO | Nivel de logging de Python |
El JS personalizado se edita y almacena mediante la página de administración
/payloads(persistido en la tablasettingsde SQLite) y se añade a/p.js. Ya no se lee desde un archivo.
blindxss-lite/
├── wsgi.py # WSGI entry point
├── requirements.txt # Python dependencies
├── Dockerfile # Container image
├── docker-compose.yml # Compose config
├── .env # Credentials (don't commit)
└── app/
├── __init__.py # App factory, CORS, health check
├── config.py # Config + .env loader
├── db.py # SQLite layer
├── collectors.py # /p.js, /c, /c.gif
├── events.py # /events admin
├── payloads.py # /payloads admin
├── utils.py # Helpers + Basic Auth decorator
├── static/
│ └── style.css
└── templates/
├── events.html
├── event.html
└── payloads.html
document.cookiePayloads:

Resultado:

Detalle del resultado:

.env nunca debe confirmarse en el control de versiones.