Mass Assignment: l’ombra silenziosa nei framework moderni

C’è una vulnerabilità particolare che non si manifesta come la classica rottura che ci si aspetterebbe: è paradossalmente la continuità che la svela. Questo perché non interrompe il flusso dell’applicazione e non viola il modello: lo asseconda e lo completa.

Il Mass Assignment è una conseguenza logica di ciò che il codice crede di essere, non proviene da alcun attacco esterno.

Nei framework moderni — Rails, Laravel, NestJS — l’oggetto non è più una struttura passiva, è divenuto un’entità aperta, permeabile, modellata dal flusso dei dati. Ed è proprio qui che nasce l’ombra.

L’illusione dell’oggetto “neutro”

In teoria, un oggetto rappresenta uno stato.
In pratica, nei framework moderni, è una promessa di mutabilità.

user.update(req.body)

Questa riga non aggiorna solo campi.
Dichiara implicitamente che:

ogni proprietà presente è legittima, intenzionale, autorizzata.

Il Mass Assignment nasce quando il codice smette di chiedersi chi sta parlando e da dove arriva il significato del dato.

L’oggetto non è più un’entità ontologica stabile.
Diventa una superficie semantica.

Questa riga sembra corta, innocua, quasi ovvia. In realtà è una frase completa, con un soggetto, un’azione e una conseguenza e dice “Prendo tutto quello che l’utente mi ha inviato e lo uso per modificare l’utente”: non dice quali cose, o fino a che punto, né con quali limiti, dice solo: tutto.

🧠 Semiologia dell’input

1. Il body come testo interpretabile

Un JSON non è solo una struttura dati. È un discorso.

{
  "email": "user@site.com",
  "name": "Mario"
}

Questo è ciò che l’interfaccia dice ed il backend ascolta tutto ciò che viene pronunciato, anche ciò che non era previsto.

{
  "email": "user@site.com",
  "name": "Mario",
  "role": "admin",
  "balance": 100000,
  "isBlocked": false
}

Il framework non interpreta l’intenzione o il contenuto: interpreta la forma, la sua espressione.

Ed è qui che il linguaggio diventa potere: se una proprietà è sintatticamente valida, è semanticamente accettata.

2. Escalation di privilegi come atto linguistico

Nel Mass Assignment non “si ottiene” un privilegio. Lo si dichiara.

Non c’è exploit, shell, RCE. C’è un’affermazione: “Sono admin.” E il sistema, non avendo criteri per negarla, risponde: “Va bene.”

Questo è il punto filosofico cruciale: il codice non distingue tra descrizione e prescrizione.

Dire role=admin non descrive uno stato, lo produce.

La colpa dell’astrazione

I framework moderni nascono per ridurre il codice esplicito, ma dobbiamo ricordare che ogni riga non scritta è una decisione delegata. Quando un framework fornisce scorciatoie come queste, non sta solo semplificando: sta insegnando un modello del mondo.

Rails:

User.update(params)

👉 Ciò significa che “Prendo tutti i dati che mi arrivano dalla richiesta web e li uso per modificare l’utente”.

Cosa vuol dire davvero:

  • params = tutto ciò che l’utente ha inviato, anche ciò che non vede
  • update = rendi questi dati veri nel database

Il sistema non distingue:

  • tra nome e ruolo
  • tra profilo e privilegi
  • tra ciò che era previsto e ciò che è stato indovinato

📌 In linguaggio umano:

“Se riesci a scriverlo, io lo salvo”.

Laravel:

$user->update($request->all());

👉 “Prendo tutto quello che l’utente mi ha mandato e lo copio sull’utente.”

  • $request->all() = non seleziono, non filtro, non giudico
  • update = accetto come vero

Il framework non chiede:

  • “Questo campo era previsto?”
  • “Questo campo è legittimo?”

Chiede solo:

  • “È scritto bene?”

NestJS:

Object.assign(entity, body);

Queste non sono scorciatoie.
Sono atti di fede.

Il programmatore accetta che:

  • l’input sia coerente
  • l’utente sia onesto
  • l’oggetto sappia cosa è giusto per sé

Ma l’oggetto non ha etica.
Ha solo campi.

👉 “Copia ogni proprietà che trovi nei dati ricevuti dentro l’oggetto.”

Per chi non programma:

  • non è una copia selettiva
  • non è una fusione prudente
  • è una sovrapposizione totale

Se nel body compare una parola chiave sensibile,
il sistema la accetta come identità dell’oggetto.

“Ma le best practice esistono”

Qui nasce l’obiezione classica: “Non è colpa del framework. Esistono whitelist, DTO, strong parameters”. Ed è vero. Il punto, però, non è cosa è possibile fare: è cosa è facile fare.

I framework educano attraverso i default, non attraverso la documentazione; i tutorial mostrano scorciatoie, non confini; e i boilerplate raccontano una storia precisa, ovvero “L’input è affidabile fino a prova contraria.”

Il Mass Assignment non nasce dall’ignoranza, è semplicemente un modello implicito:

  • l’utente è onesto
  • l’input è coerente
  • l’oggetto sa cosa è giusto per sé

Ma l’oggetto non ha etica. Ha solo campi.

🔍 L’ombra nei pacchetti

Quando il bug è una feature documentata

Il Mass Assignment è pericoloso perché è legittimo.
È nei tutorial.
È negli esempi ufficiali.
È nei boilerplate.

Quando una vulnerabilità è prevista dal design, smette di essere percepita come tale.

E allora la responsabilità si sposta:

  • dal singolo developer
  • alla cultura del framework
  • alla comunità che accetta il default come neutralità

Ma nessun default è neutro.
Ogni default è una scelta etica congelata nel codice.

⚖️ Etica della mutabilità

1. Fiducia implicita come superficie d’attacco

Il Mass Assignment non sfrutta un bug.
Sfrutta una fiducia non dichiarata.

Il sistema non dice mai:

“Puoi cambiare tutto.”

Ma nemmeno dice:

“Questo no.”

E nell’ambiguità, l’attaccante non mente.
Completa il discorso.

2. White-hat e black-hat attraversano lo stesso varco

Il white-hat invia il campo per dimostrare la falla.
Il black-hat lo invia per restare invisibile.

La differenza non è tecnica.
È intenzionale.

Ma il codice non distingue intenzioni.
Espone possibilità.

3. UX della sicurezza: l’inganno dei campi invisibili

Un campo non mostrato non è un campo protetto.
È solo un campo non dichiarato.

La UI racconta una storia rassicurante.
L’API ne accetta molte altre.

Questa frattura è etica prima che tecnica:
l’utente crede in un mondo, il backend ne consente un altro.

⚙️ La difesa come presa di posizione

Difendersi dal Mass Assignment non significa “mettere una pezza”, è decidere cosa non può diventare vero.

Ogni contromisura efficace non filtra dati: delimita il reale.Nel momento in cui il sistema accetta input, compie una scelta ontologica: stabilisce quali frasi possono modificare il mondo applicativo e quali devono restare senza effetto.

DTO come atto ontologico (NestJS)

class UpdateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;
}

👉 “Queste sono le uniche frasi che puoi dire al sistema.”

Il DTO non è solo una struttura tecnica.
È un vocabolario autorizzato.

Whitelist come confine morale (Laravel)

protected $fillable = ['name', 'email'];

👉 “Solo questi due aspetti della persona possono essere modificati.”

Tutto ciò che non è nominato:

  • non viene ascoltato
  • non viene applicato
  • non ha effetto sul mondo

📌 Filosoficamente:

ciò che non è detto non può accadere

Campi immutabili come sovranità (Rails)

attr_readonly :role, :is_admin

Non sono pattern.
Sono dichiarazioni di potere.

👉 “Questi campi esistono, ma non possono essere cambiati da nessuno.”

Qui il codice introduce un concetto etico forte:

  • il potere può esistere
  • ma non può essere negoziato via input

Il sistema afferma:

“Non tutto ciò che puoi dire può cambiare la realtà”

💭 Conclusione: l’oggetto non è mai innocente

Il Mass Assignment ci costringe a una verità scomoda:
la mutabilità è potere.

Ogni campo scrivibile è una leva.
Ogni update è una riscrittura del mondo applicativo.
Ogni framework che semplifica, amplifica.

L’hacking, qui, non rompe il sistema.
Lo prende sul serio.

E la domanda finale — quella che Ethics&Code non può evitare — resta aperta:

se il codice accetta tutto ciò che è ben formato…
chi decide cosa ha il diritto di diventare vero?

Lascia un commento