OpenAI Codex Security CLI: quanto costa davvero una scansione

Ultimo Aggiornamento: 2026-07-29 03:11:43

Un repository con un solo file e nove righe di Express può costare più di quanto ci si aspetti da uno scanner di sicurezza. Nel mio test, la nuova Codex Security CLI ha lavorato per otto minuti e mezzo prima di fermarsi contro un tetto di $6.00: 7.0 milioni di token di input consumati, un threat model di 1.605 parole generato e zero finding. Per chi pensa di inserirla nella CI, il punto essenziale è questo: il costo segue il ciclo di ragionamento dell'agente, non le righe di codice. Prima di qualsiasi altra opzione, impostate --max-cost.

Vale comunque la pena capire come funziona, anche perché è la prima versione di Codex Security eseguibile senza affidare il repository a una GitHub App.

Repository openai/codex-security su GitHub con licenza Apache-2.0 e 1.8k stelle

Codex Security CLI: cosa fa e cosa non è

Codex Security non nasce oggi. OpenAI lo aveva presentato in research preview nel marzo 2026 come servizio ospitato: si collega un repository GitHub, il sistema costruisce un threat model, analizza la cronologia dei commit in un ambiente isolato e pubblica i risultati in un workspace ChatGPT. SecurityWeek ha riportato la disponibilità per clienti ChatGPT Pro, Enterprise, Business ed Edu.

Il rilascio del 28 luglio 2026 è un'altra cosa. openai/codex-security è una CLI con SDK TypeScript sotto licenza Apache-2.0, pubblicata su npm come versione 0.1.0 alle 17:09 UTC e seguita dalla 0.1.1 alle 23:48 UTC dello stesso giorno. Al momento della stesura conta 1.8k stelle e 28 issue aperte. È un progetto appena nato.

Per l'installazione servono Node.js 22 o successivo e Python 3.10 o successivo, dato che il motore di scansione include un plugin Python:

npm install @openai/codex-security
npx codex-security info

Il modo più rapido per verificare cosa è stato installato è info:

sdkVersion: 0.1.1
bundledPluginVersion: 0.1.14
cliVersion: 0.1.1
codexVersion: 0.144.6
model: gpt-5.6-sol
reasoningEffort: xhigh

Le ultime due righe spiegano da sole il profilo dei costi. In questa installazione, le scansioni usano per impostazione predefinita GPT-5.6 Sol con livello di ragionamento xhigh. L'opzione --model permette di cambiare modello, ma il plugin è costruito attorno a un ciclo agentico profondo: ed è quel ciclo a pesare sul conto.

La superficie di comando è più ampia di quanto lasci intendere il prodotto ospitato: scan, validate, patch, scans per elencare, mostrare, rieseguire, confrontare e abbinare scansioni, bulk-scan, export in CSV, JSON o SARIF, install-hook, oltre a una modalità mcp che registra lo strumento come server MCP. Da notare che info restituisce anche scanMcp: false: le scansioni non possono essere annullate tramite il trasporto MCP.

Autenticazione: due strade, un possibile blocco

npx codex-security login effettua l'accesso con un account ChatGPT, mentre --device-auth serve per le macchine headless e OPENAI_API_KEY per la CI. Se sono presenti sia una chiave sia un accesso interattivo, le scansioni interattive chiedono quale usare; nelle esecuzioni non interattive ha priorità la chiave API.

C'è però un'avvertenza nella documentazione ufficiale da leggere con attenzione: le scansioni dell'intero repository possono richiedere anche Trusted Access for Cyber. Né il login né la configurazione di una chiave API lo concedono. Va quindi previsto un processo di richiesta accesso, non il solo accesso al servizio.

Eseguire OpenAI Codex Security CLI su un endpoint compatibile

Il primo approccio che fallisce è impostare OPENAI_API_KEY con una chiave di terze parti e aspettarsi che il traffico venga instradato lì:

codex-security: Authentication failed using OPENAI_API_KEY.

La chiave da sola non reindirizza nulla: il runtime Codex incorporato punta ancora all'URL base di OpenAI e ignora OPENAI_BASE_URL. La configurazione del provider va sovrascritta tramite --codex, che accetta valori TOML:

OPENAI_API_KEY=sk-... npx codex-security scan . --auth api-key --max-cost 5 \
  --codex 'model_provider="relay"' \
  --codex 'model_providers.relay.name="relay"' \
  --codex 'model_providers.relay.base_url="https://your-endpoint/api/v1"' \
  --codex 'model_providers.relay.env_key="OPENAI_API_KEY"' \
  --codex 'model_providers.relay.wire_api="responses"'

Due dettagli mi sono costati una singola esecuzione ciascuno. I valori senza virgolette producono Invalid --codex TOML value. Inoltre, Codex 0.144.6 rifiuta direttamente wire_api="chat", rimandando con un errore alla discussione #7782 e invitando a usare responses. L'endpoint deve quindi implementare la Responses API, non soltanto Chat Completions.

La stessa impostazione determina anche dove finisce la fattura del modello. La CLI stima sempre i costi in base ai prezzi di listino OpenAI per GPT-5.6 Sol, indipendentemente dall'endpoint selezionato: il totale progressivo è quindi un calcolo sui token, non la vostra fattura effettiva. Instradando lo stesso traffico verso un endpoint con prezzi pari alla metà del listino, l'esecuzione da $6.03 riportata più avanti costa circa $3, anche se la CLI continua a visualizzare $6.03.

Il costo di una scansione reale

I numeri seguenti vanno letti con una condizione importante: tutte e cinque le esecuzioni sono passate da endpoint di terze parti compatibili con OpenAI, perché non disponevo di un accesso ChatGPT Business o Enterprise per provare il percorso ufficiale. Questi dati misurano quindi il comportamento della CLI nelle condizioni in cui uno sviluppatore comune può usarla oggi, non quello del servizio ospitato su un account abilitato.

Il repository di test è volutamente minuscolo e volutamente vulnerabile. Nove righe, quattro difetti inseriti apposta:

const express = require('express');
const { exec } = require('child_process');
const db = require('./db');
const app = express();
const API_KEY = "sk-live-9f3a2b7c1d4e5f6a8b9c0d1e2f3a4b5c";
app.get('/u', (req, res) => db.query("SELECT * FROM users WHERE id = " + req.query.id, (e, r) => res.json(r)));
app.get('/ping', (req, res) => exec("ping -c 1 " + req.query.host, (e, o) => res.send(o)));
app.get('/f', (req, res) => res.sendFile(__dirname + "/files/" + req.query.name));
app.listen(3000);

SQL costruito concatenando stringhe, child_process.exec su un parametro della query, percorso sendFile non sanitizzato e una chiave hard-coded. Ambiente di prova: macOS, Node v22.17.0, Python 3.14.6, @openai/[email protected], plugin incluso 0.1.14; tutte le esecuzioni sono avvenute il 2026-07-29 tra le 02:20 e le 03:05 UTC.

EsecuzioneTargetBudgetArrestata aDurataInput in cacheInput nuovoOutputFinding
1Repository completo, modalità standard$1.00$1.463m23s1,092,608121,39610,3000
2Repository completo, modalità standard$6.00$6.038m33s6,654,720331,33034,9460
3Working tree, diff di una riga$3.00$3.069m46s2,035,712240,44828,1200
4Repository completo, progetto completo$8.00$8.548m00s7,299,840634,41957,2230
5Repository completo, reasoning_effort=low$3.00$3.204m13s1,749,248366,84116,2690

Le cifre in dollari sono stime della CLI stessa: vengono mostrate durante la scansione e salvate in scans list. Sono calcolate dai conteggi dei token ai prezzi di listino OpenAI, non in base a quanto fattura davvero un endpoint; l'input in cache spiega perché i totali appaiano bassi rispetto ai token complessivi. L'esecuzione 2 torna esattamente usando $5.00 per milione di token di input nuovo, $0.50 per milione di input in cache e $30.00 per milione di token di output:

331,330 x $5.00/M   = $1.657
6,654,720 x $0.50/M = $3.327
34,946 x $30.00/M   = $1.048
                      ------
                      $6.032   (CLI reported $6.03239)

Le stesse tre tariffe riproducono al centesimo i totali di tutte e cinque le esecuzioni: un utile controllo di coerenza se i vostri numeri dovessero sembrare anomali.

Nessuna delle cinque scansioni è arrivata alla fine. Si sono tutte fermate per il budget e scans list le riporta come phase: preflight, status: failed con coverage: worklistRows 0: nessuna ha raggiunto la fase che restituisce le vulnerabilità.

L'esecuzione 4 è il controllo. Il primo repository era intenzionalmente incompleto: mancava package.json e veniva importato ./db, ma il modulo non esisteva. Il threat model dello strumento ha segnalato esplicitamente questa incognita. Ricostruito correttamente con quattro file e tredici righe, dipendenze dichiarate, è costato di più anziché meno: $8.54 e 7.9M di token di input.

Accumulo del costo stimato durante otto minuti di scansione di un repository di nove righe

La crescita non è lineare. Nei primi tre minuti il costo aumenta lentamente, poi compie due salti; ogni salto coincide con l'ampliamento del lavoro dell'agente. Il log dichiara il meccanismo una sola volta, al 51° secondo: Preflight: worker delegation supported (up to 8 worker slots).

Ripartizione dei token: 6.65M token di input in cache, 0.33M di input nuovo e 35k di output

Il 95% dei token di input era costituito da letture della cache: lo stesso contesto veniva quindi reinviato turno dopo turno, non letto di nuovo. Il costo unitario è basso, ma resta la voce più pesante. Sette milioni di token si fanno sentire anche alle tariffe dell'input in cache, persino per un file di nove righe.

È qui che la stima spesso ripetuta di circa $0.02 per 1.000 righe di codice smette di avere senso. Con quella formula, il mio repository sarebbe dovuto costare una frazione di centesimo.

Ridurre il reasoning aiuta, ma meno del previsto

L'esecuzione 5 imposta model_reasoning_effort="low" sullo stesso progetto dell'esecuzione 4. Il consumo è sceso da circa 1.0M a 0.5M token al minuto: a parità di dollari, il tempo di elaborazione raddoppia. Ha comunque raggiunto il proprio limite nella stessa fase di preflight, senza nulla da riportare. Dimezzare la velocità di consumo non basta se la pipeline richiede comunque più turni di quanti il budget ne possa coprire.

--max-cost è un checkpoint, non un freno

Confronto tra budget impostato e costo al momento dell'arresto per cinque esecuzioni con limiti da $1 a $8

La documentazione ufficiale della CLI avverte che le richieste già in corso possono completarsi oltre il limite. Non indica però di quanto. Nelle cinque esecuzioni, lo sforamento è andato dallo 0.5% al 46%: il limite di $1.00 ha portato a un arresto a $1.46, quello di $6.00 a $6.03, mentre i tre limiti intermedi sono finiti dal 2% al 7% oltre soglia. Lo sforamento corrisponde al lavoro che l'agente aveva già in volo; il caso costoso è un fan-out di worker che termina vicino al tetto. Impostate quindi il limite sotto la cifra che non potete superare.

Il pre-commit non è la scorciatoia economica

La risposta più ovvia a una scansione completa fuori controllo è analizzare soltanto ciò che è cambiato. Ho creato un commit di base pulito, aggiunto una riga vulnerabile — una clausola LIKE costruita con concatenazione di stringhe — ed eseguito --working-tree --base HEAD.

È costata più della prima scansione completa: 9m46s, 2,276,160 token di input, arresto a $3.06 contro un tetto di $3.00. È avanzata più delle scansioni complete, arrivando a scrivere una worklist di revisione ordinata per priorità (rank_input.jsonl, deep_review_input.jsonl) prima di esaurire il budget, ma non ha prodotto finding. Limitare l'analisi a un diff non riduce il contesto per turno: l'agente continua a leggere il repository, a generare un threat model completo e a distribuire il lavoro ai worker.

install-hook collega lo strumento a un hook Git pre-commit che blocca i finding ad alta gravità e gli errori di scansione. Prima di installarlo per un team, vale la pena misurare una singola scansione diff sul proprio codebase: è un hook che può aggiungere minuti e dollari a ogni commit.

I limiti che restano

Il threat model prodotto dallo strumento per nove righe è un buon lavoro. Identifica tutti e quattro i confini di fiducia, considera il modulo mancante ./db un'incognita esplicita e non attribuisce a Express protezioni che non può verificare. Ne esplicita anche il limite: "Controls not present in the repository must not be assumed."

È un vincolo strutturale. L'unico input è il codice sorgente, quindi tutto ciò che viene deciso al deploy resta invisibile: policy CORS, debug mode lasciata attiva, TLS debole, security header assenti, cache poisoning e autorizzazione runtime fra servizi. I difetti di autorizzazione a livello di oggetto, in particolare, richiedono richieste autenticate di due identità reali per essere confermati: nessuna lettura del sorgente può fornirle.

Anche la profondità di analisi per linguaggio sembra non essere uniforme. Un resoconto pratico sul servizio ospitato indica una copertura più solida per Python, JavaScript, TypeScript, Go e Java, con Ruby, PHP e Kotlin più indietro. Ho testato soltanto JavaScript, quindi questa è un'informazione di seconda mano.

Vale la pena usarla?

Installatela oggi se vi interessa il threat model. È l'unico artefatto ricevuto in ogni esecuzione: un documento di 1.605 parole che mappa i confini di fiducia, elenca gli scenari d'attacco e definisce cosa significhino critical, high, medium e low per quello specifico servizio. Può inoltre alimentare gli altri strumenti che già usate, dato che --knowledge-base accetta la documentazione dell'architettura e il modello generato è modificabile.

Aspettate se vi servono spesa prevedibile o un elenco concreto di finding. In cinque configurazioni non ho ottenuto né l'una né l'altro, spendendo da $1.46 a $8.54 per esecuzione su un repository leggibile in dieci secondi. Gli output documentati nelle fasi successive — findings.json, coverage.json e report.md — non li ho mai raggiunti. Se un account ChatGPT Business abilitato si comporti diversamente resta la domanda a cui questi test non possono rispondere.

Nessuna delle due leve di costo più ovvie ha funzionato qui: né limitare al diff né abbassare il reasoning effort hanno superato lo stesso ostacolo. Quella che modifica davvero l'aritmetica è la tariffa del modello, perché la stima deriva dai token ai prezzi di listino; un endpoint a metà listino dimezza il costo della stessa esecuzione. Fate budget sulle esecuzioni misurate, non sulle dimensioni del repository, e tenete il limite sotto quello reale di almeno un giro di worker: il mio peggior sforamento è stato il 46% del tetto.

FAQ

Codex Security CLI è gratuita?

CLI e SDK sono sotto licenza Apache-2.0 e non costano nulla da installare. Le scansioni non sono gratuite: consumano token GPT-5.6 Sol sulla credenziale usata per l'autenticazione e la CLI mostra una stima progressiva ai prezzi di listino OpenAI.

Serve un piano ChatGPT Business o Enterprise?

Per l'integrazione GitHub ospitata, sì: quel percorso è limitato a Pro, Enterprise, Business ed Edu. La CLI accetta una normale OPENAI_API_KEY, ma la documentazione avverte che le scansioni dell'intero repository possono richiedere comunque Trusted Access for Cyber, che nessun piano concede automaticamente.

Può essere eseguita in CI?

Sì. Impostate OPENAI_API_KEY, aggiungete --fail-on-severity per trasformare i finding in un codice di uscita diverso da zero e puntate CODEX_SECURITY_STATE_DIR a un percorso scrivibile fuori dal repository. Per impostazione predefinita, le scansioni producono solo report.

Funziona con un endpoint di terze parti compatibile con OpenAI?

Sì, purché l'endpoint implementi la Responses API. Bisogna sovrascrivere la configurazione del provider Codex con i flag --codex, perché impostare soltanto OPENAI_API_KEY porta a un errore di autenticazione.

In cosa differisce la CLI dal plugin Codex Security?

Il motore di scansione è lo stesso, cambia il punto d'accesso. Il plugin viene eseguito nell'infrastruttura OpenAI su un repository GitHub collegato. La CLI gira sulla propria macchina contro un percorso locale, conserva la cronologia delle scansioni in una directory di stato locale e aggiunge scansioni limitate ai diff, hook pre-commit, export SARIF e registrazione MCP.


Approfondimenti correlati: Guida ai prezzi di GPT-5.6 · Codex auto mode