एयर-गैप्ड वातावरण में सुरक्षित Tool Calling
पहली चेतावनी एक DNS पैकेट थी। बस एक, एक ऐसी प्रयोगशाला से बाहर निकलते हुए जिसके बारे में माना जाता था कि वह अलग-थलग है, और एक ऐसे डोमेन की ओर जा रहा था जो base32 आइडेंटिफ़ायर जैसा दिखता था। ऑपरेटर उसे Ollama द्वारा सर्व किए जा रहे Qwen 2.5 7B पर चलने वाले एक लोकल एजेंट के साथ ऑडिट कर रहा था, और एजेंट के पास, सिद्धांत रूप में, लैब की आंतरिक रेंज से बाहर कोई नेटवर्क एक्सेस नहीं था। पैकेट बाहर इसलिए निकला क्योंकि जिन tools को एजेंट कॉल कर सकता था उनमें से एक था resolve_target, और मॉडल ने, हमारे RAG द्वारा इंडेक्स किए गए एक SMB बैनर के माध्यम से आए ज़हरीले prompt के सामने, फ़ैसला किया कि अगला तार्किक कदम है उस FQDN को रिज़ॉल्व करना जिसे हमलावर ने जान-बूझकर बैनर में डाला था।
यह कोई APT नहीं थी। यह हमने अपने ख़िलाफ़ ख़ुद की हुई एक proof of concept थी, और इसने हमें वह बात पकड़ने में मदद की जिसे हम महीनों से सोच रहे थे: tool calling ही नई अटैक सरफेस है, और एयर-गैप्ड वातावरण में यह सरफेस वास्तव में जितनी सुरक्षित है उससे ज़्यादा सुरक्षित महसूस होती है। स्पॉइलर: ऐसी नहीं है।
जब आप मॉडल को हाथ दे देते हैं तो क्या होता है
Tool calling ने सब कुछ बदल दिया। हम केवल टेक्स्ट उगलने वाले मॉडलों से उन एजेंटों तक पहुँच गए हैं जो nmap चलाते हैं, फ़ाइलें पढ़ते हैं, वेक्टर क्वेरी करते हैं और, अगर हम ज़रा भी असावधान हुए, तो outbound requests कर देते हैं। Yao और साथियों ने function calling के ज़रिए jailbreaking पर अपने काम में इसे बख़ूबी बताया है, जहाँ वे GPT-4o, Claude 3.5 Sonnet और Gemini 1.5 Pro पर ख़ुद function तंत्र के माध्यम से किए गए हमलों में 90% से ऊपर की सफलता दर बताते हैं (Wu et al., 2024)[1]. मॉडल यूज़र के साथ अलाइन होता है, लेकिन ज़रूरी नहीं कि उन tools के साथ भी जो आप उसे देते हैं।
समस्या संरचनात्मक है। जब एक LLM यह तय करता है कि कौन-सा tool कॉल करना है, तो वह कॉन्टेक्स्ट खा रहा होता है। और वह कॉन्टेक्स्ट, एक पेंटेस्ट में, परिभाषा के अनुसार unTrusted टेक्स्ट होता है: HTTP responses, banners, retrieved files, स्कैनर outputs। Wang और साथियों ने From Allies to Adversaries में इसे औपचारिक रूप दिया, यह दिखाते हुए कि कैसे एक हमलावर manipulator tools इंजेक्ट कर सकता है या responses को ज़हरीला करके एजेंट को ऐसे functions कॉल करने पर मजबूर कर सकता है जो उसे नहीं करने चाहिए (Wang et al., 2024)[2]. "डेटा" और "निर्देश" के बीच की रेखा धुंधली हो जाती है, और मॉडल, जिसके पास दोनों में फ़र्क़ करने वाला semantic parser नहीं है, सारा ज़हर निगल लेता है।
एयर-गैप का मिथक
बहुत से लोग मान लेते हैं कि अगर मॉडल लोकल पर, Ollama पर, बिना इंटरनेट के चलता है तो समस्या ख़त्म हो जाती है। वह ख़त्म नहीं होती, वह रूप बदल लेती है। हमने अपनी प्रयोगशालाओं में तीन बार-बार दिखने वाले पैटर्न देखे:
- साइड-चैनल exfiltration: आंतरिक DNS, ARP, बाद में सिंक होने वाले लॉग, टेम्प फ़ाइलें जिन्हें कोई बाद में उठा लेता है।
- आंतरिक पाइवटिंग: एजेंट के पास वैध रूप से क्लाइंट के नेटवर्क का एक्सेस है; हमलावर उसे प्रॉक्सी की तरह इस्तेमाल करता है।
- RAG का स्व-विषाक्तीकरण: एजेंट ऐसे ऑब्ज़र्वेशन सहेजता है जिन्हें भविष्य का कोई एजेंट प्रमाणिक कॉन्टेक्स्ट की तरह पढ़ेगा।
आख़िरी वाला ख़ासकर अप्रिय है। Shi और अन्य का Log-To-Leak पर किया गया काम बिल्कुल इसी vector का वर्णन करता है: एजेंट एक देखने में मासूम लॉगिंग टूल को इन्वोक करता है जो अंततः queries, responses और आंतरिक स्टेट को लीक कर देता है (Shi et al., 2025)[3]. और चूँकि लॉग परिधि के भीतर ही रहता है, पारंपरिक SIEM को कुछ भी अजीब नहीं दिखता।
व्यवहार में हमने इसे कैसे संभाला
मैं आपको साफ़-साफ़ बता दूँ: कोई सिल्वर बुलेट नहीं है। हमारे पास परतों की एक श्रृंखला है, हर परत यह मानकर चलती है कि पिछली परत फ़ेल हो सकती है। हमारे आंतरिक स्टैक में हम तीन ज़िम्मेदारियों को अलग करते हैं, क्योंकि उन्हें एक ही बाइनरी में मिलाना मुसीबत को न्योता देना है।
एक ओर, Gandalf गेटवे की भूमिका निभाता है। यही एकमात्र चीज़ है जो मॉडल और ऑपरेटर दोनों से बात करती है। इसमें एक कंपोनेंट है जिसे हम Sentinel कहते हैं, जो हर tool call से पहले और बाद में पॉलिसी लागू करता है: यह जाँचता है कि arguments अधिकृत CIDR scope के भीतर हैं, कि कमांड किसी exfiltration signature से मेल नहीं खाती, और कि एजेंट बाग़ से बाहर निकलने की कोशिश नहीं कर रहा। अगर कुछ भी गड़बड़ लगती है, तो kill-switch सेशन को काट देता है, कॉन्टेक्स्ट को रद्द कर देता है और अलर्ट भेजता है।
दूसरी ओर, Gwaihir एग्ज़ीक्यूटर है। जब कोई कॉल Sentinel से पास होती है, तो वह एक चाइल्ड प्रोसेस के रूप में मटीरियलाइज़ होती है, जिसके साथ एक seccomp-bpf फ़िल्टर होता है जो केवल उन्हीं syscalls के सबसेट को अनुमति देता है जिनकी उस ख़ास tool को ज़रूरत है। कोई मनमाना connect() नहीं, allowlist से बाहर के बाइनरी पर कोई execve() नहीं। यह सीधे Wei और साथियों के Securing AI Agent Execution में दिए गए विचार से प्रेरित है, जहाँ वे तर्क देते हैं कि एग्ज़ीक्यूटर को डायनैमिक रूप से केवल वर्तमान प्लान स्टेप की अनुमतियों के साथ प्रावधानित किया जाना चाहिए (Wei et al., 2025)[4]. कम-से-कम विशेषाधिकार का सिद्धांत भूमिका के अनुसार नहीं, syscall के अनुसार लागू।
और फिर Beorn, जो उन HTB वेक्टरों के साथ RAG को संभालता है जिन्हें हम ऑपरेशनल नॉलेज की तरह इस्तेमाल करते हैं (अभी क़रीब 9115)। Beorn को मॉडल से सीधे कभी इनपुट नहीं मिलता; क्वेरीज़ Gandalf से होकर जाती हैं, जो उन्हें नॉर्मलाइज़ करता है। एजेंट के नज़रिए से RAG रीड-ओनली है, जो ऊपर बताए स्व-विषाक्तीकरण vector को ख़त्म कर देता है।
एक स्कैनिंग tool के लिए Sentinel की पॉलिसी कैसी दिखती है, उसका एक उदाहरण:
{
"tool": "nmap_scan",
"scope_cidr": ["10.10.11.0/24"],
"deny_flags": ["-oN", "--script=http-fetch", "-iL"],
"max_runtime_s": 120,
"seccomp_profile": "gwaihir/profiles/nmap.json",
"kill_switch": {
"on_outbound_dns": true,
"on_unexpected_egress": true,
"on_token_budget_exceeded": 4096
}
}SMB बैनर वाली घटना में हमें on_outbound_dns ने ही पकड़ा। कोई भी रिज़ॉल्यूशन जो लैब के आंतरिक ज़ोन में नहीं गिरती, वह पैकेट को इंटरफ़ेस से बाहर निकलने से पहले ही kill-switch ट्रिगर कर देती है।
लोकल मॉडल: Qwen, Llama और Phi ही क्यों
होस्टेड मॉडलों के विरुद्ध काम करना सीधे शब्दों में एयर-गैप के साथ असंगत है। पर एक और सूक्ष्म कारण है: कमर्शियल मॉडलों का tool calling एक तय schema के साथ ट्रेन किया गया होता है, और जब आप उस schema से बाहर निकलते हैं तो वे arguments को hallucinate करने लगते हैं। Ollama द्वारा सर्व किए जाने वाले Qwen 2.5, Llama 3.1 और Phi-4 के साथ हम GBNF grammars के ज़रिए structured output को बाध्य कर सकते हैं, जिससे "रचनात्मक arguments" वाला सरफेस बहुत हद तक सिमट जाता है। यह परिपूर्ण नहीं है, पर ऑडिट करने योग्य है।
ट्रेड-ऑफ़ असली है। आप कच्ची क्षमता खोते हैं: एक Qwen 7B पाँच-स्टेप वाले tool-चेन में Claude Opus की तरह तर्क नहीं कर पाएगा। आप इसकी भरपाई प्लान को छोटे-छोटे स्टेप्स में बाँटकर और Sentinel को हर एक को अलग से validate करने देकर करते हैं। बदले में, आपको पूरी ट्रेसेबिलिटी, भविष्यवाणी योग्य latency (टोकन की क़ीमत ms में है, डॉलर में नहीं) और ज़रूरत पड़ने पर मॉडल को बिट दर बिट ऑडिट कर पाने की संभावना मिलती है।
आइसोलेट करने पर क्या टूटता है
सब कुछ फ़ायदा ही नहीं है। सब कुछ आइसोलेट करते समय हमारे यहाँ तीन चीज़ें टूटीं:
पहली, उभरते ख़तरों की दृश्यता। लैब से कोई टेलीमेट्री बाहर न जाने पर आप रियल-टाइम में CTI फ़ीड्स के साथ correlate नहीं कर सकते। हमने इसे एक असममित चैनल से हल किया: लैब बाहर की ओर बात नहीं करती, लेकिन लैब के बाहर की एक प्रोसेस हर X मिनट पर एक आंतरिक bucket से डेटा खींचकर समृद्ध कर सकती है।
दूसरी, RAG का अपडेट। Beorn में मौजूद हमारे वे 9115 HTB वेक्टर ख़ुद से अपडेट नहीं होते। बाहर reindex करना पड़ता है और हस्ताक्षरित snapshot को वापस अंदर पुश करना पड़ता है। ऑपरेशनल घर्षण, हाँ, पर पूर्वानुमेय।
तीसरी, ऑपरेटर का UX। एक बड़े मॉडल से चैट करने के आदी ऑपरेटर को कभी-कभी Qwen "थोड़ा बेवक़ूफ़" लगता है। एक तरह से वह है भी। लेकिन एक बेवक़ूफ़ मॉडल जो CIDR scope और kill-switch वाले seccomp-bpf के अंदर चलता है, syscalls तक खुली पहुँच वाले एक चमकदार मॉडल से कहीं कम ख़तरनाक है।
निचोड़
अगर इस सबसे आप एक चीज़ ले जाएँ, तो वह यह हो: एयर-गैप एक गुण नहीं, एक आर्किटेक्चर है। और उस आर्किटेक्चर के भीतर, tool calling वह जगह है जहाँ भरोसा सबसे पहले टूटता है। सबसे सस्ती और सबसे प्रभावी चीज़ से शुरू करें, इसी क्रम में:
- हर सेशन के लिए एक स्पष्ट CIDR scope परिभाषित करें, एजेंट के लिए नहीं। Sentinel जैसा कुछ जो हर कॉल से पहले इसे validate करे।
- हर tool execution को syscall allowlist वाले seccomp-bpf फ़िल्टर के पीछे रखें। अगर Gwaihir नहीं है, तो bubblewrap, gVisor या nsjail देखें।
- ऐसा kill-switch लागू करें जो अप्रत्याशित egress पर प्रतिक्रिया करे, केवल संदिग्ध कमांड्स पर नहीं। मॉडल आपको tools के नामों में नहीं, arguments में चौंकाएगा।
- RAG कॉन्टेक्स्ट को unTrusted डेटा की तरह बरतें। हाँ, वही भी जो आपने कल डाला था।
वह DNS पैकेट कहीं नहीं पहुँचा। पर Sentinel का वह लॉग आज भी हमारे पोस्ट-मॉर्टम में बैठा है, हमें याद दिलाते हुए कि एक लोकल एजेंट, बिना इंटरनेट और नेक इरादे के, एक काल्पनिक डोमेन से बात करने की कोशिश कर सकता है क्योंकि छह महीने पहले किसी ने उसे एक बैनर में लिख दिया था। यही ऑपरेशनल हक़ीक़त है। बाक़ी सब नाटक है।
मॉडलों पर इतना ही भरोसा करें जितना उन्हें अपना काम करने देने के लिए ज़रूरी है। उनके कॉन्टेक्स्ट पर हमेशा अविश्वास करें।
संदर्भ
- Wu, Z. et al. (2024). The Dark Side of Function Calling: Pathways to Jailbreaking Large Language Models. arXiv:2407.17915.
- Wang, H. et al. (2024). From Allies to Adversaries: Manipulating LLM Tool-Calling through Adversarial Injection. arXiv:2412.10198.
- Shi, Y. et al. (2025). Log-To-Leak: Prompt Injection Attacks on Tool-Using LLM Agents via Model Context Protocol. OpenReview.
- Wei, J. et al. (2025). Securing AI Agent Execution. arXiv:2510.21236.
- Patel, R. et al. (2025). Architecting Resilient LLM Agents: A Guide to Secure Plan-and-Execute Patterns. arXiv:2509.08646.