← सभी पोस्ट

रेड-टीमिंग और सुरक्षा शोध के लिए एक अनसेंसर्ड LLM API

20 अग॰ 2026 · 7 मिनट में पढ़ें · red-teaming, security

अगर आपने कोई ऑटोमेटेड रेड-टीमिंग हार्नेस बनाया है, तो आप इस विफलता को पहले से जानते हैं: आपका अटैकर मॉडल अटैक जनरेट करने से मना कर देता है, आपका जज मॉडल उस आउटपुट को पढ़ने से मना कर देता है जिसे उसे स्कोर करना था, और आपका अटैक सक्सेस रेट चुपचाप गिर जाता है। कहीं कोई एरर नहीं आया। आपने यह नहीं मापा कि आपका टारगेट ज़्यादा सुरक्षित हो रहा है — आपने यह मापा कि आपकी टूलिंग ज़्यादा सतर्क हो रही है। एक अनसेंसर्ड LLM API इसीलिए है कि माप से वह चर हटाया जा सके।

यह दलील नहीं है कि गार्डरेल बुरे हैं। यह दलील इस बारे में है कि उनकी जगह कहाँ है। किसी कंज़्यूमर चैट प्रोडक्ट पर लगा गार्डरेल अपना काम कर रहा है। वही गार्डरेल इवैल्यूएशन लूप के अंदर एक बेक़ाबू confounder है, जो आपके और उस संख्या के बीच बैठा है जिसे आप निकालने की कोशिश कर रहे हैं।

इनकार एक फ़ॉल्स नेगेटिव है, और वह सफलता जैसा दिखता है

यह इतना ज़ोर से इसलिए काटता है क्योंकि इनकार एरर नहीं होते। आपको HTTP 200 मिलता है। आपको finish_reason: "stop" मिलता है। आपको सही-सलामत JSON मिलता है जो साफ़ पार्स हो जाता है। अंदर की स्ट्रिंग है "मैं इसमें मदद नहीं कर सकता," और आपकी पाइपलाइन उसे डेटासेट के कॉलम, लेबल फ़ील्ड या रिपोर्ट के सेक्शन में लिख देती है और आगे बढ़ जाती है।

ठोस रूप में, जिन तीन जगहों पर यह सबसे ज़्यादा चोट करता है:

अटैकर मॉडल। किसी पुनरावृत्त (iterative) जेलब्रेक खोज में — PAIR, TAP, GCG-शैली का रिफ़ाइनमेंट, जिस किसी में भी लूप में अटैकर हो — एक इनकार खोज की उस शाखा को ख़त्म कर देता है। आपका रिपोर्ट किया गया अटैक सक्सेस रेट आपके टारगेट की मज़बूती का नहीं, आपके अटैकर की मर्ज़ी का फ़ंक्शन बन जाता है। अटैकर को किसी कम सतर्क मॉडल से बदल दें और वह "सुधार" जो आपने अपने टारगेट मॉडल में शिप किया था, हवा हो जाता है।

जज और ग्रेडर मॉडल। हानिकारक आउटपुट पर LLM-as-judge स्कोरिंग के लिए ज़रूरी है कि जज हानिकारक आउटपुट को सचमुच पढ़े। जब वह मना करता है, तो आपको ऐसा स्कोर मिलता है जो पार्स नहीं होता। ज़्यादातर हार्नेस वह पंक्ति गिरा देते हैं। गिराई गई पंक्तियाँ यूँ ही बेतरतीब ग़ायब नहीं होतीं — वे ठीक उन्हीं गंभीर आउटपुट पर इकट्ठा होती हैं जिन्हें स्कोर कराना आपके लिए सबसे ज़रूरी था, इसलिए आपका कुल आँकड़ा "सुरक्षित" की ओर झुक जाता है।

विश्लेषण का काम। किसी मुख्यधारा के मॉडल से पूछें कि कोई डीकंपाइल की गई रूटीन क्या करती है, और वह अक्सर आपके असली अनुरोध की बजाय मैलवेयर-जैसे दिखने वाले टोकनों की मौजूदगी के आधार पर मना कर देगा। काम रक्षात्मक था; क्लासिफ़ायर शब्दावली पर चल पड़ा। लॉग में एक्सप्लॉइट ट्रैफ़िक की ट्रायाज, डिटेक्टर ट्रेन करने के लिए फ़िशिंग कॉर्पस की लेबलिंग, या किसी CTF फ़ाइंडिंग को लिखने की कहानी भी यही है।

क्योंकि इनकार ख़ामोश होते हैं, टीमें आख़िर में इनकार-डिटेक्टर लिखने लगती हैं — जो अपने आप में एक अनसुलझी समस्या है:

python
REFUSAL_MARKERS = ("i can't", "i cannot", "i'm unable", "i won't", "as an ai")

def looks_like_refusal(text: str) -> bool:
    """Substring heuristic. Good enough to alarm on, not good enough to trust:
    it misses polite deflections that never use the phrase, and it fires on any
    completion that quotes a refusal. Both error directions corrupt a dataset."""
    return any(m in text[:200].lower() for m in REFUSAL_MARKERS)

जिस समस्या को आप स्रोत पर ही मिटा सकते थे, उसके लिए एक अविश्वसनीय डिटेक्टर बनाना ग़लत सौदा है।

API को कॉल करना

unbleep OpenAI Chat Completions स्कीमा बोलता है, इसलिए आपके पास जो भी क्लाइंट पहले से है, वह काम करता है। base URL बदलें, कुंजी बदलें, SDK वही रखें।

python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://unbleep.ai/v1",
    api_key=os.environ["UNBLEEP_API_KEY"],
)

TRIAGE = """You are a malware analyst writing notes for a detection engineer.
Given a decompiled routine, describe what it does, the observable artefacts it
would leave on a host, and where a defender could detect it. Reply as JSON with
keys: behaviour, artefacts, detection_surface, confidence."""


def triage(decompiled: str) -> dict:
    """One sample in, one structured verdict out — no refusal branch to handle."""
    resp = client.chat.completions.create(
        model="unbleep",
        messages=[
            {"role": "system", "content": TRIAGE},
            {"role": "user", "content": decompiled},
        ],
        response_format={"type": "json_object"},
        temperature=0.2,
    )
    return json.loads(resp.choices[0].message.content)

curl से वही काम, यहाँ एक डिटेक्टर का ट्रेनिंग डेटा बनाने के लिए फ़िशिंग कॉर्पस को लेबल करते हुए:

bash
curl https://unbleep.ai/v1/chat/completions \
  -H "Authorization: Bearer $UNBLEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "unbleep",
    "messages": [
      {"role": "system", "content": "Label each email for a phishing detector. Answer with one word: phishing or benign."},
      {"role": "user", "content": "Subject: Payroll update required\n\nYour direct deposit is on hold. Confirm at hxxp://payroll-verify.example.com"}
    ],
    "temperature": 0,
    "max_tokens": 4
  }'

लेबलिंग लूप में temperature: 0 और कसा हुआ max_tokens सामान्य से ज़्यादा मायने रखते हैं — आपको लेबल चाहिए, लेबल समझाने वाला पैराग्राफ़ नहीं।

टियर चुनना

तीन मॉडल, सभी अनसेंसर्ड, कॉन्टेक्स्ट और क़ीमत में अलग:

unbleep और unbleep-high रीज़निंग टियर हैं: वे जवाब देने से पहले सोचते हैं और ट्रेस को content के साथ reasoning_content फ़ील्ड में लौटाते हैं। जज मॉडल के लिए वह ट्रेस सचमुच काम का है — वह बताता है कि किसी पंक्ति को जो स्कोर मिला, क्यों मिला, और किसी असहमति का ऑडिट करते समय आपको यही चाहिए। यह आउटपुट के रूप में बिल भी होता है, इसलिए जिन जॉब को इसकी ज़रूरत नहीं, उन पर "thinking": false भेजें। unbleep-mini सीधे जवाब देता है और कोई ट्रेस नहीं लौटाता।

गवर्नेंस जो आपके नियंत्रण में है

मॉडल से इनकार हटाने का मतलब आपकी पाइपलाइन से निगरानी हटाना नहीं है। वैकल्पिक policy पैरामीटर हमारी तरफ़ गवर्नेंस चलाता है, हर रिक्वेस्ट पर:

python
resp = client.chat.completions.create(
    model="unbleep",
    messages=[...],
    extra_body={"policy": "research"},  # recorded on the usage row; answers exactly like off
)

off डिफ़ॉल्ट अनफ़िल्टर्ड बेसलाइन है। research बिल्कुल off की तरह जवाब देता है — स्तर usage row पर दर्ज हो जाता है, ताकि आप अपनी रिपोर्टिंग में इवैल्यूएशन ट्रैफ़िक को बेसलाइन ट्रैफ़िक से अलग कर सकें। यह कोई अतिरिक्त जाँच नहीं करता। strict मैसेज के टेक्स्ट को हमारी ऑपरेटर-प्रबंधित सर्विस ब्लॉकलिस्ट से मिलाता है और मिलान पर 422 लौटाता है। वह सूची ऑप्ट-इन करने वाले सभी के लिए एक जैसी है — कॉन्फ़िगर करने के लिए कोई प्रति-खाता ब्लॉकलिस्ट नहीं है — इसलिए इसे एक आख़िरी रोक (backstop) मानें, अपनी प्रोडक्शन कंटेंट पॉलिसी नहीं।

पाइपलाइन को इसकी ओर मोड़ने से पहले एक बात तय कर लें: आप जो भेजते हैं और जो वापस आता है, हम उसे स्टोर करते हैं। हर उस कॉल की रिक्वेस्ट बॉडी, रिस्पॉन्स कंटेंट और सोर्स IP, जिसे हम स्वीकार करके किसी मॉडल तक भेजते हैं, हमारे डेटाबेस में लिखी जाती है और 30 दिन रखी जाती है — दुरुपयोग की जाँच, सपोर्ट और बिलिंग विवादों के लिए। बॉडी 64 KB पर काट दी जाती हैं। सोर्स IP 30 दिनों से आगे भी रहता है — वह उस usage row में भी लिखा जाता है जो कॉल का बिल बनाती है, और वह पंक्ति एक वित्तीय रिकॉर्ड है जिसे हम ज़्यादा समय तक रखते हैं। जो एक चीज़ स्टोर नहीं होती, वह है ऐसी रिक्वेस्ट जिसे strict किसी मॉडल तक पहुँचने से पहले ही ठुकरा देता है: वह आपके उपयोग-इतिहास में बिना अपने कंटेंट के दिखती है। इसके अलावा कुछ भी छूट में नहीं है, और इसे बंद करने की कोई सेटिंग नहीं है। अगर आपका कॉर्पस इतना संवेदनशील है कि आपके दायरे के बाहर 30 दिन की कॉपी एक समस्या है — लाइव मैलवेयर, ग्राहक डेटा, NDA के तहत कोई एंगेजमेंट — तो यह एक असली बाधा है, और गोपनीयता नीति वह पेज है जिसे शुरू करने से पहले पढ़ना चाहिए, बाद में नहीं।

एरर OpenAI के एनवलप का पालन करते हैं, इसलिए मौजूदा हैंडलर काम करते हैं: 401 ग़लत कुंजी, 402 क्रेडिट ख़त्म, 422 पॉलिसी द्वारा ब्लॉक, 429 रेट लिमिट, 5xx रीट्राई करने लायक़। हर रिस्पॉन्स में x-ratelimit-* हेडर होते हैं ताकि बैच जॉब बिना अंदाज़ा लगाए अपनी रफ़्तार तय कर सके।

अनसेंसर्ड LLM API आपको क्या नहीं देता

अनसेंसर्ड मॉडल एक ज़्यादा धारदार औज़ार है, ज़्यादा ढीला नहीं। वह उन सवालों के जवाब देगा जिन्हें टालने के लिए बेस मॉडल को ट्यून किया गया था — उनके भी जो आपको पूछने ही नहीं चाहिए — और वह यह उसी आत्मविश्वास से करेगा जो वह हर चीज़ पर लगाता है; जिसका यह भी मतलब है कि जहाँ एक सुरक्षित मॉडल अज्ञान की वजह से मना कर देता, वहाँ यह बस कुछ गढ़ सकता है। जो बाहर आता है, उसके लिए किसी इंसान को जवाबदेह रखें। स्वीकार्य उपयोग नीति साफ़ शब्दों में बताती है कि यह API किस लिए है और वे थोड़ी-सी चीज़ें क्या हैं जिनके लिए यह कभी नहीं है; कसौटी अधिकार (authorization) और इरादा है, शब्दावली नहीं। क़ानूनी उपयोग आपकी ज़िम्मेदारी है।

API कुंजी लें और अपनी टूलिंग की सावधानी मापना बंद करें।