Python pratico

eval e pickle: alternative sicure per dati e config in Python

19 min di lettura
Primo piano di un vecchio lucchetto arrugginito chiuso attorno a un anello di ferro corroso, su uno sfondo sfocato nei toni del rosa e del beige
Windows macOS Linux
Foto: Engin Akyurt · Pexels · Licenza Pexels

Perché eval() e pickle su dati non fidati eseguono codice, e cosa usare al loro posto: literal_eval, json, tomllib, configparser, validazione, firma HMAC.

Hai chiesto all’IA di salvare le impostazioni del gestionale o la cache dei clienti tra un avvio e l’altro, e lo script funziona. Dentro però trovi impostazioni = eval(open("config.txt").read()) oppure clienti = pickle.load(f). Nella guida alle 7 falle di sicurezza nel codice scritto dall’IA è la falla numero 6; qui vedi cosa mettere al loro posto, con codice che puoi copiare. eval() e pickle non leggono dati: eseguono istruzioni. Se il testo o il file arriva da qualcuno che non sei tu, quel qualcuno sceglie cosa fa il tuo programma.

La risposta breve: per strutture semplici scritte come Python usa ast.literal_eval(); per scambiare o salvare dati usa json; per i file di configurazione tomllib (Python 3.11 e successivi) o configparser; poi valida quello che hai letto con una dataclass o con pydantic. Se pickle non si può togliere, firma i file con HMAC e rifiuta quelli che non tornano. Per YAML, solo yaml.safe_load(). In fondo trovi uno script da scaricare che mostra la differenza e cerca questi schemi nei tuoi file.

ℹ️ Nota / Prerequisito operativo: ti serve Python 3.11 o successivo (per tomllib) e un terminale. Su Windows usa Prompt dei comandi o PowerShell e il comando python; su macOS e Linux il Terminale e python3. Controlla la versione con python --version (Windows) o python3 --version (macOS/Linux). Solo gli esempi con pydantic e PyYAML richiedono pacchetti esterni; gli altri usano la libreria standard.

Perché eval e pickle eseguono codice

eval() prende una stringa e la valuta come espressione Python, con accesso a tutto quello che il programma può fare. Se la stringa è {'porta': 8080} ottieni un dizionario; se è __import__('os').remove('clienti.db') ottieni un file cancellato. exec() fa lo stesso con interi blocchi di codice. Non esiste una lista di «parole pericolose» da filtrare in modo affidabile: il linguaggio offre troppi modi per arrivare agli stessi moduli.

pickle sembra un formato di dati, ma quando ricostruisce un oggetto può chiamare una funzione scelta da chi ha creato il file (è il meccanismo __reduce__). La documentazione ufficiale del modulo pickle lo dice in apertura: il modulo non è sicuro, e caricare dati pickle da fonti non fidate può eseguire codice arbitrario. Lo stesso vale per tutto ciò che usa pickle sotto: shelve, joblib.load(), molti file .pkl di modelli di machine learning scaricati da Internet.

«Non fidato» qui significa più cose di quanto sembri: un file caricato da un utente, un allegato, un campo di un modulo web, una cache in una cartella condivisa o sincronizzata (Dropbox, OneDrive, una share di rete dello studio), un file scaricato da un repository. Se un’altra persona o un altro programma può scrivere quel file, trattalo come non fidato.

La differenza vista in pratica

Lo script controlla_eval_pickle.py (SHA-256 c4194e1ad2046cbaab090e6f447cf8ee813d96eb0511120a88788fb83de3bd7f) contiene una dimostrazione innocua: il «codice malevolo» si limita a creare un file eseguito.txt in una cartella temporanea, che lo script cancella alla fine. Usa solo la libreria standard e non apre connessioni di rete.

Salvalo nella cartella Download, verifica l’hash e lancia la demo.

Windows (PowerShell):

cd $HOME\Downloads
Get-FileHash .\controlla_eval_pickle.py -Algorithm SHA256
python controlla_eval_pickle.py --demo

macOS / Linux (Terminale):

cd ~/Downloads
shasum -a 256 controlla_eval_pickle.py
python3 controlla_eval_pickle.py --demo

L’hash deve coincidere con quello scritto sopra (PowerShell lo mostra in maiuscolo: è lo stesso valore); se è diverso, non eseguire il file. Su alcune distribuzioni Linux usa sha256sum controlla_eval_pickle.py al posto di shasum.

Output su macOS 15.7.7 (Python 3.14.7) e Debian 13 (Python 3.13.5), identico sui due sistemi:

Input simulato: una riga di "config" che in realta' e' codice
  __import__('pathlib').Path('<temp>/eseguito.txt').write_text('x')

1) VULNERABILE: eval() sul testo
   file eseguito.txt creato? SI

2) SICURO: ast.literal_eval() sullo stesso testo
   rifiutato: ValueError, malformed node or string
   file eseguito.txt creato? no
   literal_eval su dati veri: {'porta': 8080, 'debug': False}

3) VULNERABILE: pickle.loads() su un file manomesso
   file eseguito.txt creato? SI

4) SICURO: json.loads() - accetta solo dati
    {'porta': 8080, 'debug': False, 'clienti': ['rossi', 'bianchi']}
   testo malevolo rifiutato: Expecting value

5) SICURO: tomllib per i file di configurazione
    {'porta': 8080, 'debug': False, 'database': {'percorso': 'dati/clienti.db'}}

6) SE PICKLE E' INEVITABILE: firma HMAC prima di caricare
   file originale: {'porta': 8080}
   file manomesso: firma non valida: file non caricato
   file eseguito.txt creato? no

Cartella temporanea eliminata.

Nei casi 1 e 3 il file compare: al posto di una scrittura innocua poteva esserci qualsiasi comando, con i permessi del tuo utente. Nel caso 3 non c’è nemmeno bisogno di usare l’oggetto caricato: basta pickle.loads(). Negli altri casi lo stesso contenuto viene rifiutato o non viene mai caricato.

Le alternative, una per una

Strumento Esegue codice? Quando usarlo
eval / execlibreria standard Sì Mai su testo che arriva da fuori. Per dati e configurazione non serve.
pickle / shelvelibreria standard Sì Solo per file creati e letti dallo stesso programma, in una cartella che nessun altro scrive; meglio se firmati con HMAC.
ast.literal_evallibreria standard No Testo già scritto come letterale Python (dizionari, liste, tuple, numeri, stringhe, True/False/None).
jsonlibreria standard No Salvare e scambiare dati: cache, esportazioni, API. Leggibile anche da altri linguaggi.
tomlliblibreria standard, Python 3.11+ No File di configurazione scritti a mano, con tipi (numeri, booleani, date) e sezioni. Solo lettura.
configparserlibreria standard No File .ini semplici, anche su Python vecchi. Tutto arriva come testo: converti con getint/getboolean.
yaml.safe_loadpacchetto PyYAML Solo safe_load Quando il formato YAML è imposto (Docker Compose, CI). yaml.load con UnsafeLoader esegue codice.

Nessuno dei formati sicuri controlla che i valori abbiano senso: una porta "8080" scritta come testo o un percorso ../../ passano la lettura senza errori. Per questo ogni esempio qui sotto finisce con una validazione.

ast.literal_eval(): al posto di eval() per i letterali

Se il programma salvava le impostazioni con str(dizionario) e le rileggeva con eval(), la sostituzione più piccola è ast.literal_eval(): accetta solo stringhe, byte, numeri, tuple, liste, dizionari, insiemi, booleani e None.

import ast

testo = "{'porta': 8080, 'host': '127.0.0.1', 'clienti': ('rossi', 'bianchi')}"
print(ast.literal_eval(testo))

for prova in ["2 + 2", "[x for x in range(3)]", "__import__('os').getcwd()"]:
    try:
        print(prova, "->", ast.literal_eval(prova))
    except ValueError as e:
        print(prova, "-> rifiutato:", str(e).split(" on line")[0])

Output, uguale su macOS e Debian:

{'porta': 8080, 'host': '127.0.0.1', 'clienti': ('rossi', 'bianchi')}
2 + 2 -> rifiutato: malformed node or string
[x for x in range(3)] -> rifiutato: malformed node or string
__import__('os').getcwd() -> rifiutato: malformed node or string

Anche 2 + 2 viene rifiutato: niente operatori, chiamate o variabili. Un limite da conoscere: la documentazione di ast avverte che un input molto grande o annidato può esaurire memoria o stack e far terminare l’interprete. Su testo che arriva dalla rete, limita la lunghezza prima di passarlo (per esempio rifiuta tutto ciò che supera qualche kilobyte) e preferisci JSON.

json + dataclass: dati e configurazione validati

JSON è la scelta più semplice per salvare e rileggere dati: json.load() produce solo dizionari, liste, stringhe, numeri, booleani e None. Salva questo file come config.json:

{
  "porta": 8080,
  "host": "127.0.0.1",
  "debug": false,
  "cartella_dati": "dati/clienti"
}

E nella stessa cartella leggi_json.py:

import json
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class Config:
    porta: int
    host: str
    debug: bool
    cartella_dati: str

    def __post_init__(self):
        if not isinstance(self.porta, int) or not 1 <= self.porta <= 65535:
            raise ValueError(f"porta non valida: {self.porta!r}")
        if not isinstance(self.debug, bool):
            raise ValueError(f"debug deve essere true/false, non {self.debug!r}")
        if Path(self.cartella_dati).is_absolute() or ".." in Path(self.cartella_dati).parts:
            raise ValueError(f"cartella_dati fuori dal progetto: {self.cartella_dati!r}")


def carica(percorso):
    with open(percorso, encoding="utf-8") as f:
        dati = json.load(f)
    return Config(**dati)


cfg = carica("config.json")
print(cfg)

for errato in ['{"porta": "8080", "host": "x", "debug": false, "cartella_dati": "d"}',
               '{"porta": 8080, "host": "x", "debug": false, "cartella_dati": "../../etc"}',
               '{"porta": 8080, "host": "x", "debug": false, "cartella_dati": "d", "admin": true}']:
    try:
        Config(**json.loads(errato))
    except (ValueError, TypeError) as e:
        print("rifiutato:", e)

Lancialo con python leggi_json.py (Windows) o python3 leggi_json.py (macOS/Linux):

Config(porta=8080, host='127.0.0.1', debug=False, cartella_dati='dati/clienti')
rifiutato: porta non valida: '8080'
rifiutato: cartella_dati fuori dal progetto: '../../etc'
rifiutato: Config.__init__() got an unexpected keyword argument 'admin'

Tre dettagli che fanno la differenza. Le annotazioni di tipo di una dataclass non vengono controllate da Python: i controlli li scrivi tu in __post_init__. Config(**dati) rifiuta da sola le chiavi in più (come admin) e quelle mancanti. frozen=True impedisce di modificare la configurazione per errore dopo il caricamento. Per salvare usa json.dump(dati, f, ensure_ascii=False, indent=2), con il file aperto in scrittura e encoding="utf-8".

tomllib: file di configurazione scritti a mano

TOML è il formato di pyproject.toml: commenti, sezioni e tipi veri (un 8080 resta un intero). Da Python 3.11 il modulo tomllib è nella libreria standard e serve solo a leggere. Salva config.toml:

porta = 8080
host = "127.0.0.1"
debug = false

[database]
percorso = "dati/clienti.db"
timeout = 5.0

e leggi_toml.py:

import tomllib

with open("config.toml", "rb") as f:
    cfg = tomllib.load(f)

print(cfg["porta"], type(cfg["porta"]).__name__)
print(cfg["database"]["percorso"])

try:
    tomllib.loads('porta = __import__("os").getcwd()')
except tomllib.TOMLDecodeError as e:
    print("rifiutato:", e)

Output:

8080 int
dati/clienti.db
rifiutato: Invalid value (at line 1, column 9)

Il file va aperto in modalità binaria ("rb"): con "r" ottieni un TypeError. Il dizionario risultante si valida come sopra, passando le chiavi alla tua dataclass.

configparser: i classici file .ini

Se il programma ha già un config.ini, non serve cambiare formato:

[server]
porta = 8080
debug = no

[database]
percorso = dati/clienti.db
import configparser

cfg = configparser.ConfigParser(interpolation=None)
cfg.read("config.ini", encoding="utf-8")

porta = cfg.getint("server", "porta")
debug = cfg.getboolean("server", "debug")
percorso = cfg.get("database", "percorso")
print(porta, debug, percorso)
print(type(cfg["server"]["porta"]).__name__)

Output: 8080 False dati/clienti.db e poi str. Ogni valore è testo finché non lo converti con getint(), getfloat() o getboolean() (che accetta yes/no, on/off, true/false, 1/0). interpolation=None disattiva la sostituzione %(nome)s, così un % dentro una password non provoca errori. Attenzione: cfg.read() ignora in silenzio un file che non esiste; se il file è obbligatorio, controlla il valore restituito (la lista dei file letti).

pydantic: validazione completa in poche righe

Se il progetto ha già dipendenze esterne, pydantic fa la validazione al posto tuo. Installalo in un ambiente virtuale attivo:

Windows:

python -m pip install pydantic
python -c "import pydantic; print(pydantic.VERSION)"

macOS / Linux:

python3 -m pip install pydantic
python3 -c "import pydantic; print(pydantic.VERSION)"

L’installazione termina con Successfully installed … pydantic-…; il secondo comando stampa la versione (nei miei test 2.14.1). Se sul Mac il comando sembra non fare nulla o import fallisce, quasi sempre il venv non è attivo o stai usando un altro Python.

import json
from pydantic import BaseModel, ConfigDict, Field, ValidationError


class Config(BaseModel):
    model_config = ConfigDict(extra="forbid", strict=True)
    porta: int = Field(ge=1, le=65535)
    host: str
    debug: bool = False
    cartella_dati: str


with open("config.json", encoding="utf-8") as f:
    cfg = Config.model_validate(json.load(f))
print(cfg)

try:
    Config.model_validate({"porta": 70000, "host": "x", "cartella_dati": "d", "admin": True})
except ValidationError as e:
    print(e.error_count(), "errori")
    for err in e.errors():
        print("-", err["loc"], err["msg"])

Output:

porta=8080 host='127.0.0.1' debug=False cartella_dati='dati/clienti'
2 errori
- ('porta',) Input should be less than or equal to 65535
- ('admin',) Extra inputs are not permitted

extra="forbid" rifiuta le chiavi non previste; strict=True impedisce le conversioni automatiche (senza, "8080" diventerebbe 8080); Field(ge=1, le=65535) fissa i limiti. pydantic riporta tutti gli errori in una volta, non solo il primo.

YAML: solo safe_load

Con PyYAML (python -m pip install pyyaml su Windows, python3 -m pip install pyyaml su macOS/Linux) la regola è una sola: yaml.safe_load().

import yaml

sicuro = """
porta: 8080
clienti: [rossi, bianchi]
"""
print(yaml.safe_load(sicuro))

malevolo = "!!python/object/apply:os.getcwd []"
try:
    yaml.safe_load(malevolo)
except yaml.constructor.ConstructorError as e:
    print("safe_load rifiuta:", e.problem)

print("yaml.load con Loader=yaml.UnsafeLoader esegue:", yaml.load(malevolo, Loader=yaml.UnsafeLoader))

Con PyYAML 6.0.3, safe_load risponde could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/apply:os.getcwd', mentre UnsafeLoader esegue davvero os.getcwd() e stampa la cartella corrente. Dalla versione 6.0 yaml.load() senza Loader dà errore, quindi nel codice generato dall’IA trovi spesso Loader=yaml.Loader o yaml.FullLoader aggiunti per «farlo funzionare»: sostituiscili con yaml.safe_load().

Se pickle è inevitabile: firma il file con HMAC

A volte pickle resta: una cache di oggetti complessi, un modello salvato da una libreria che non offre altro. In quel caso il file deve dimostrare di essere stato scritto dal tuo programma prima di essere caricato.

Busta di carta marrone chiusa con un sigillo di ceralacca rossa, appoggiata su un tavolo di legno accanto a ritagli di carta gialla e a un pennino
Come un sigillo di ceralacca, la firma HMAC non nasconde il contenuto: dice se qualcuno l’ha aperto e richiuso. Foto: John-Mark Smith · Pexels
import hashlib
import hmac
import os
import pickle

CHIAVE = os.environ["CHIAVE_CACHE"].encode()


def salva(oggetto, percorso):
    dati = pickle.dumps(oggetto)
    firma = hmac.new(CHIAVE, dati, hashlib.sha256).digest()
    with open(percorso, "wb") as f:
        f.write(firma + dati)


def carica(percorso):
    with open(percorso, "rb") as f:
        contenuto = f.read()
    firma, dati = contenuto[:32], contenuto[32:]
    attesa = hmac.new(CHIAVE, dati, hashlib.sha256).digest()
    if not hmac.compare_digest(firma, attesa):
        raise ValueError(f"{percorso}: firma non valida, file non caricato")
    return pickle.loads(dati)


salva({"modello": "v3", "pesi": [0.12, 0.88]}, "cache.bin")
print(carica("cache.bin"))

with open("cache.bin", "r+b") as f:
    f.seek(-3, os.SEEK_END)
    f.write(b"XYZ")
try:
    carica("cache.bin")
except ValueError as e:
    print(e)

Salvalo come pickle_firmato.py. La chiave arriva da una variabile d’ambiente, mai scritta nel codice.

Windows (PowerShell):

$env:CHIAVE_CACHE = "una-chiave-lunga-e-casuale"
python pickle_firmato.py

Windows (Prompt dei comandi):

set CHIAVE_CACHE=una-chiave-lunga-e-casuale
python pickle_firmato.py

macOS / Linux:

CHIAVE_CACHE=una-chiave-lunga-e-casuale python3 pickle_firmato.py

Output:

{'modello': 'v3', 'pesi': [0.12, 0.88]}
cache.bin: firma non valida, file non caricato

Il file modificato non arriva mai a pickle.loads(). Per una chiave vera generane una con python -c "import secrets; print(secrets.token_hex(32))" (python3 su macOS e Linux) e conservala fuori dal progetto. Usa sempre hmac.compare_digest() e non ==, che può rivelare informazioni dai tempi di confronto. Il limite: la firma protegge da chi può scrivere il file ma non conosce la chiave. Non rende sicuro un file .pkl scaricato da Internet, perché in quel caso il «firmatario» sarebbe proprio la fonte di cui non ti fidi.

Cerca eval, pickle e yaml.load nei tuoi script

La seconda funzione di controlla_eval_pickle.py è uno scanner. Legge i file .py senza eseguirli (analizza la struttura con il modulo ast) e segnala:

  • ALTO: eval() o exec() su un valore calcolato mentre il programma gira; pickle.load/loads, marshal, dill, joblib.load; yaml.load senza un loader Safe, yaml.unsafe_load, yaml.full_load;
  • MEDIO: eval()/exec() con una stringa fissa, shelve.open().

ast.literal_eval() e yaml.safe_load() non vengono segnalati. Dalla cartella del tuo progetto:

Windows (Prompt dei comandi):

python %USERPROFILE%\Downloads\controlla_eval_pickle.py .

Windows (PowerShell):

python $HOME\Downloads\controlla_eval_pickle.py .

macOS / Linux:

python3 ~/Downloads/controlla_eval_pickle.py .

Le opzioni:

  • percorso (default .): la cartella o il singolo file .py da analizzare. Esempio: python controlla_eval_pickle.py gestionale.py.
  • --escludi NOME: salta una cartella con quel nome; ripetibile (--escludi test --escludi vecchi). .venv, venv, env, node_modules, .git, __pycache__, site-packages, build e dist sono già esclusi.
  • --demo: la dimostrazione vista sopra.
  • --version e -h: versione e aiuto.

Su un mini progetto d’esempio con gestionale.py (impostazioni lette con eval, clienti con pickle.load, un YAML con Loader=yaml.Loader e uno con safe_load) e strumenti/report.py, l’output è identico su macOS e Debian:

[ALTO] gestionale.py:5  eval() su un valore calcolato a runtime
[ALTO] gestionale.py:9  pickle.load(): esegue codice se il file e' manomesso
[ALTO] gestionale.py:12  yaml.load() senza SafeLoader: usa yaml.safe_load()
[MEDIO] strumenti/report.py:4  eval() con stringa fissa: serve davvero?
[MEDIO] strumenti/report.py:6  shelve.open(): usa pickle sotto
[ALTO] strumenti/report.py:7  exec() su un valore calcolato a runtime

File .py analizzati: 2
Segnalazioni: 6 (ALTO 4, MEDIO 2, ERRORE 0)

Il yaml.safe_load() e l’ast.literal_eval() presenti nei due file non compaiono, e nemmeno un pickle.loads() messo apposta nella cartella .venv. Codici di uscita: 1 se trova qualcosa, 0 se non trova nulla, 2 se il percorso non esiste (o se Python è più vecchio della 3.11). Puoi usarlo come controllo prima di un commit.

💡 Consiglio pratico — Cosa non vede lo scanner: cerca solo le chiamate scritte in modo diretto (pickle.load, yaml.load…). Non riconosce from pickle import load seguito da load(f), né funzioni passate tramite variabili, né le librerie che usano pickle internamente. Nessuna segnalazione significa «nessuno di questi schemi», non «codice sicuro».

Errori tipici

  • ValueError: malformed node or string dopo il passaggio a literal_eval() → il testo contiene espressioni, variabili o chiamate (anche solo 2 + 2 o datetime(…)) → salva i dati come letterali puri o passa a JSON.
  • TypeError: Object of type datetime is not JSON serializable → JSON conosce solo tipi base → converti prima (data.isoformat()) e ricostruisci in lettura con datetime.fromisoformat().
  • TypeError: File must be opened in binary mode con tomllib.load() → hai aperto il file con "r" → usa open("config.toml", "rb").
  • configparser restituisce "8080" invece di 8080 → tutti i valori sono testo → usa getint(), getfloat(), getboolean().
  • TypeError: load() missing 1 required positional argument: 'Loader' con PyYAML 6 → la soluzione è yaml.safe_load(), non aggiungere Loader=yaml.Loader.
  • KeyError: 'CHIAVE_CACHE' con il pickle firmato → la variabile d’ambiente non è impostata nel terminale in cui lanci lo script → impostala come mostrato sopra, nella stessa finestra.

Domande Frequenti (FAQ)

eval() è sicuro se tolgo __builtins__?

No. eval(testo, {"__builtins__": {}}) è un trucco noto ma aggirabile: partendo da un qualsiasi oggetto Python si risale alle classi interne e da lì ai moduli. Non esiste un modo affidabile di rendere eval() sicuro su testo non fidato; se ti serve valutare formule (per esempio prezzo * 1.22), usa un parser dedicato o limita l’input a numeri e operatori controllati.

Pickle è sicuro se il file l’ho creato io?

Il formato non cambia: il rischio dipende da chi può modificare il file dopo che l’hai creato. Una cache nella cartella del tuo utente, letta solo dal tuo programma, è un uso accettabile; lo stesso file in una cartella condivisa, sincronizzata o caricata da un utente no. In quel caso firmalo con HMAC o passa a JSON.

Che differenza c’è tra json e pickle per salvare dati?

JSON salva solo dati (testo, numeri, liste, dizionari) ed è leggibile da altri programmi e linguaggi; leggerlo non esegue codice. Pickle salva quasi qualunque oggetto Python, comprese istanze di classi, ma leggerlo può eseguire codice ed è legato a Python. Per configurazione, cache semplici ed esportazioni, JSON basta quasi sempre.

tomllib può anche scrivere i file TOML?

No, tomllib legge soltanto. Per scrivere serve un pacchetto esterno come tomli-w (python -m pip install tomli-w su Windows, python3 -m pip install tomli-w su macOS/Linux). Spesso non serve: i file di configurazione li scrivi a mano, e i dati che il programma salva da solo stanno meglio in JSON.

Come carico in sicurezza un modello .pkl scaricato da Internet?

Non esiste un modo sicuro di caricare un pickle di cui non ti fidi. Cerca lo stesso modello in un formato che contiene solo dati, come safetensors per i pesi delle reti neurali, oppure scaricalo solo dalla fonte ufficiale e verifica l’hash pubblicato. Se devi proprio aprirlo, fallo in una macchina virtuale o in un ambiente usa e getta, senza dati veri.

yaml.FullLoader è sicuro?

È più restrittivo di UnsafeLoader, ma in passato ha avuto vulnerabilità che permettevano l’esecuzione di codice, corrette nelle versioni successive di PyYAML. Per file di configurazione non ti serve nessuna funzione che SafeLoader non abbia: usa yaml.safe_load() e non ci pensi più.

Dopo la correzione

Sostituito l’ultimo eval e l’ultimo pickle.load, rilancia lo scanner: l’obiettivo è nessuna riga ALTO e solo MEDIO che hai letto e deciso di tenere. Quando chiedi codice all’IA, puoi indicare già il formato giusto con i prompt di sicurezza specifici invece di quelli generici. Se nello stesso script trovi anche comandi di sistema costruiti con stringhe, la guida ai pattern sicuri per shell=True e subprocess in Python segue lo stesso metodo. Per le altre falle da cercare, torna alla guida madre sulle 7 falle di sicurezza nel codice scritto dall’IA.

Alex Lunalbi

Alex Lunalbi

Security & privacy

Dona su PayPal

Scrivo di sicurezza digitale pratica e codice IA. Su ai riparo ogni procedura è verificata su macchine reali.

Tag
  • python,
  • sicurezza,
  • pickle,
  • json,
  • vibe coding