flawopen.com/Teardowns/cve-2026-104873-langgraph-sdk-auth-action-bypass
LangGraph CVE-2026-104873: bypass otorisasi
LangGraph SDK 0.1.45–0.4.3 mengabaikan filter tindakan pada tiga dekorator Python. Perbarui ke 0.4.4.[1]
Bayangkan resepsionis gedung yang hanya menerima paket, tetapi sistem mengarahkan semua pengunjung ke mejanya. Jika resepsionis hanya memeriksa bahwa seseorang sudah masuk, pengunjung dapat mencapai ruangan yang seharusnya dikunci meja lain. SDK mengabaikan actions= saat mendaftarkan handler resource, sehingga operasi baca, ubah, atau hapus juga dapat diterima. Risiko muncul jika handler tidak memeriksa izin.[1]
Konsep Kunci & Istilah
CWE-863- Otorisasi tidak benar: pemeriksaan tidak menerapkan izin yang dimaksud.[1]
Pemetaan kerangka kerja
- Referensi CWE untuk kelemahan yang dijelaskan dalam panduan ini: CWE-863
- OWASP API Security Top 10 — API5:2023 Otorisasi Tingkat Fungsi yang Tidak Tepat
Analisis Akar Masalah (Root Cause)
Versi 0.1.45–0.4.3 menerima actions=, tetapi mendaftarkan handler pada wildcard resource *. LangGraph dapat memilihnya sebelum fallback umum. Jika fungsi hanya mengizinkan tindakan yang dimaksud, tindakan lain dapat diterima tanpa pemeriksaan fallback. Akses ke resource orang lain memerlukan aplikasi yang bergantung pada pemeriksaan terlewat dan handler yang tidak memeriksa tindakan serta kepemilikan sendiri. Versi 0.4.4 memvalidasi daftar dan mendaftarkan tiap tindakan secara terpisah; tanpa actions=, wildcard tetap dipertahankan dengan sengaja. Advisory menetapkan CWE-863 dan CVSS 4.0 7.6 High. Ini kelemahan otorisasi bergantung konfigurasi, bukan bypass tanpa autentikasi atau masalah semua deployment LangGraph. Dekorator yang terdampak adalah: @auth.on.threads / @auth.on.assistants / @auth.on.crons. Batas penting perbaikan: perubahan SDK membatasi pendaftaran pada tindakan yang dideklarasikan, tetapi jalur custom-auth yang tidak tercakup tetap diizinkan jika aplikasi tidak mengatur handler global dengan default-deny. Changelog 0.4.4 menyebut langgraph-api 0.10+ memperingatkan jalur yang tidak tercakup saat startup; perlakukan peringatan itu sebagai deteksi, bukan penegakan akses.[1], [2], [5]
Alur Serangan Langkah demi Langkah
Kode Sumber: Rentan vs Aman
Cuplikan rentan menunjukkan perilaku lama: _ResourceOn.__call__ memakai * tanpa memedulikan actions=. Perbaikan memvalidasi daftar dan mendaftarkan tindakan satu per satu. Ini cuplikan, bukan pengganti modul lengkap. Perbarui SDK dan periksa tindakan serta kepemilikan di handler. Lokasi kode sumber: libs/sdk-py/langgraph_sdk/auth/__init__.py, method _ResourceOn.__call__.[1], [2]
Cuplikan sumber: Pendaftaran handler berdasarkan tindakan
def __call__(self, fn=None, *, resources=None, actions=None):
if fn is not None:
_validate_handler(fn)
return typing.cast("_ActionHandler", _register_handler(
self.auth, self.resource, "*", fn
))
def decorator(handler):
_validate_handler(handler)
return typing.cast("_ActionHandler", _register_handler(
self.auth, self.resource, "*", handler
))
return decorator
def __call__(self, fn=None, *, resources=None, actions=None):
def decorator(handler):
_validate_handler(handler)
if resources is None:
resource_list = [self.resource]
elif isinstance(resources, str):
resource_list = [resources]
elif isinstance(resources, Sequence):
resource_list = list(resources)
else:
raise TypeError("resources must be a string or sequence of strings")
if resource_list != [self.resource]:
raise ValueError("use @auth.on(...) for other resources")
if actions is None:
action_list = ["*"]
elif isinstance(actions, str):
action_list = [actions]
elif isinstance(actions, Sequence):
action_list = list(actions)
else:
raise TypeError("actions must be a string or sequence of strings")
if not action_list:
raise ValueError("actions must not be empty")
if not all(isinstance(action, str) for action in action_list):
raise TypeError("actions must be strings")
valid_actions = {
value.action for value in vars(self).values()
if isinstance(value, _ResourceActionOn)
}
invalid_actions = (
sorted(set(action_list) - valid_actions) if actions is not None else []
)
if invalid_actions:
raise ValueError("invalid action for this resource")
if len(action_list) != len(set(action_list)):
raise ValueError("actions must not contain duplicates")
for action in action_list:
if (self.resource, action) in self.auth._handlers:
raise ValueError("handler already registered for action")
for action in action_list:
_register_handler(self.auth, self.resource, action, handler)
return handler
if fn is not None:
return decorator(typing.cast("_ActionHandler", fn))
return decorator
Daftar Periksa Penguatan Sistem Rekayasa
- ✓Perbarui SDK 0.1.45–0.4.3 ke 0.4.4+.[1], [3]
- ✓Cari tiga dekorator terdampak yang memakai
actions=.[1], [2] - ✓Periksa tindakan dan akses ke ID resource yang tepat.[1]
- ✓Uji tindakan yang dinyatakan, tidak dinyatakan, dan ditolak.[2]
- ✓Uji akses lintas pengguna ke thread, assistant, dan cron.[1]
- ✓Tolak daftar duplikat, kosong, atau tidak dikenal saat startup.[2]
- ✓Jangan samakan login dengan otorisasi eksplisit.
- ✓Atur handler global default-deny untuk setiap jalur custom-auth yang tidak tercakup oleh handler khusus tindakan. langgraph-api 0.10+ memperingatkan jalur yang tidak tercakup, tetapi peringatan startup tidak menolak permintaan.[5], [1]