Configuración
Con vantor-shield/auto, las opciones se leen de vantor.config.json en el directorio de trabajo. Con protect(), se pasan como argumento. onEvent solo funciona con protect().
Opciones
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
mode | monitor, block, off | monitor | Modo general |
rules | objeto | Modo por regla, por ejemplo { "sql": "block" }. Reglas: sql, command, path, ssrf, input, ratelimit, decoy, leak | |
license | texto | Tu licencia. Se recomienda usar VANTOR_LICENSE | |
pact | learn, monitor, block u objeto | Apagado | Ver Pacto |
decoy | objeto | Rutas señuelo activas | paths, values, banMinutes. Ver Carnadas |
leak | objeto | Activa | markers. Ver Fugas |
telemetry | booleano u objeto | true | Enviar contadores a tu panel. Nunca valores ni direcciones IP |
headers | booleano u objeto | Activas en block | Ver abajo |
rateLimit | objeto o false | false | max, windowMs (60000) y routes |
trustProxy | número | 0 | Proxies delante de la aplicación |
ignorePaths | lista | Prefijos que se saltean por completo, como /health | |
ssrfAllowHosts | lista | Hosts permitidos aunque los elija el cliente | |
maxInspectBytes | número | 5 MB | Mayor cuerpo de texto inspeccionable |
log | booleano | true | Escribir eventos en stderr |
logInputs | booleano | true | Incluir en los eventos los primeros 40 caracteres del valor |
onEvent | función | Recibe cada evento. Si falla, no afecta la petición |
headers
headers: {
csp: { // false para no enviarla
directives: { 'img-src': "'self'" },
nonce: true, // agrega un nonce a script-src
reportOnly: false,
},
hstsMaxAge: 15552000, // 0 para no enviarla
custom: {
'X-Frame-Options': 'DENY',
'Referrer-Policy': null, // null la quita
},
}
Variables de entorno
| Variable | Qué hace |
|---|---|
VANTOR_LICENSE | Tu licencia |
VANTOR_MODE | monitor, block u off. Tiene prioridad sobre la configuración |
VANTOR_TELEMETRY | off para no enviar nada al panel |
Eventos
Cada hallazgo genera un evento, una sola vez por petición:
interface ShieldEvent {
id: string;
at: string; // ISO 8601
rule: 'sql' | 'command' | 'path' | 'ssrf' | 'input' | 'ratelimit' | 'pact' | 'decoy' | 'leak';
action: 'monitored' | 'blocked';
sink: string; // por ejemplo "pg.query", "supabase.rest" o "fs.readFile"
source?: string; // path, query, body, header, cookie, params
inputLength?: number;
inputPreview?: string; // primeros 40 caracteres, salvo logInputs: false
detail?: string; // qué se comparó, en pact, decoy y leak
location?: string; // primer frame de tu código, cuando se puede obtener
request: { id: string; method: string; path: string; ip: string };
}
Privacidad: los eventos completos solo van a stderr y a onEvent, en tu servidor. Al panel llegan solo contadores y rutas sin identificadores. inputPreview puede contener datos del usuario. Si tus logs salen de tu control o guardan datos sensibles, usá logInputs: false. La query string nunca se incluye en request.path.
API
protect(options?)
Inicia Vantor. Devuelve { stop() }, que quita todos los hooks. Llamarlo de nuevo solo actualiza las opciones.
guardSql(query, { dialect? })
Revisa una consulta a mano y la devuelve. Lanza VantorBlockedError si encuentra una inyección y el modo es block. dialect puede ser pg, mysql, sqlite o generic (por defecto).
cspNonce()
El nonce de la petición actual. Requiere headers.csp.nonce.
html y escapeHtml(valor)
Escapan valores para HTML:
import { html } from 'vantor-shield';
res.send(html`<p title="${titulo}">${comentario}</p>`);
Sirven para texto y atributos entre comillas. No son seguros dentro de <script>, <style>, ni en atributos que contienen URLs como href.
VantorBlockedError
| Propiedad | Valor |
|---|---|
code | VANTOR_BLOCKED |
status, statusCode | 403 |
rule | La regla que bloqueó |
sink | Dónde se bloqueó |
app.use((err, req, res, next) => {
if (err.code === 'VANTOR_BLOCKED') return res.status(403).json({ error: 'Operación no permitida' });
next(err);
});
Respuestas de Vantor
Cuando responde directamente, sin pasar por tu código:
| Estado | Cuerpo | Cuándo |
|---|---|---|
403 | {"error":"blocked","rule":"...","requestId":"..."} | Regla input, o un bloqueo sin manejador de errores |
413 | {"error":"body_not_inspectable",...} | Cuerpo imposible de inspeccionar |
429 | {"error":"too_many_requests",...} | Rate limit |