# सुरक्षित AI Agents के लिए Discovery Calls बनाम Mutation Calls

जो agent किसी system को बहुत व्यापक रूप से inspect कर सकता है और फिर लापरवाही से उसमें बदलाव भी कर सकता है, उसे गलत तरह का अधिकार मिला है। उपयोगी विभाजन सरल है: agent को इतना discover करने दें कि वह वास्तविक स्थिति पर आधारित plan बना सके, फिर उन operations के चारों ओर स्पष्ट सीमा लगाएँ जो state create, modify, trigger या delete करते हैं।

यह विभाजन सुनने में स्पष्ट लगता है, जब तक आपका सामना किसी असली API से न हो। कोई supposedly read-only endpoint cache refresh कर देता है। कोई preview remote job allocate कर देता है। कोई update endpoint खाली filter स्वीकार करके हर record को छू लेता है। कोई SSH command harmless दिखती है, लेकिन shell expansion एक सीमित path को बहुत बड़े path में बदल देती है। Production account को method names और अच्छे इरादे सुरक्षित नहीं रखते।

मैंने teams को हर call के सामने human रखकर यह समस्या हल करते देखा है। इससे account एक दोपहर तक सुरक्षित रहता है, और शुक्रवार तक सब लोग बिना पढ़े approval देना सीख जाते हैं। बेहतर design agent को inspect करने की जगह देता है, state changes को स्पष्ट बनाता है और वहाँ सबसे मजबूत friction लगाता है जहाँ गलत action का परिणाम irreversible या महँगा हो सकता है।

## Discovery को अलग permission shape चाहिए

Discovery calls को current state के बारे में सवालों का जवाब देना चाहिए, बिना उस state को बदले। Mutation calls किसी चीज़ को create, edit, execute या remove करने की कोशिश करती हैं। यह फर्क महत्वपूर्ण है, क्योंकि agent stale guesses के आधार पर सुरक्षित plan नहीं बना सकता। लेकिन केवल context की ज़रूरत होने से उसे कार्रवाई का स्थायी अधिकार भी नहीं मिलना चाहिए।

Deployment failure की जाँच कर रहे coding agent को services की list, recent events, configuration revision की तुलना, repository status और remote issue पढ़ने की ज़रूरत हो सकती है। ये requests uncertainty कम करती हैं। अगर आप हर request पर approval लगाएँगे, तो operator को छोटे-छोटे prompts की कतार दिखाई देगी, जिनका आकलन करने के लिए पर्याप्त context नहीं होगा। Agent भी इंतज़ार करते हुए अपनी investigation की कड़ी खो देगा।

बाद में यही agent workload restart कर सकता है, pull request merge कर सकता है, credential rotate कर सकता है, issue बंद कर सकता है या object delete कर सकता है। इनमें से हर operation agent के context window से बाहर की दुनिया को बदलता है। Authorize करने से पहले operator को प्रस्तावित target और effect दिखाई देना चाहिए।

यह broad «read-only» role देने और काम पूरा मान लेने जैसा नहीं है। Discovery से sensitive material उजागर हो सकता है। इससे cost लग सकती है, rate limits खर्च हो सकती हैं या खराब design वाली service में कोई behavior activate हो सकता है। यह विभाजन action को नियंत्रित करने के बारे में है, inspection को harmless घोषित करने के बारे में नहीं।

एक उपयोगी classification यह देखती है कि request पूरी होने के बाद remote system में क्या दिखाई देगा:

1. Discovery call information लौटाती है और किसी relevant business, operational या billing state को नहीं बदलती।
2. Mutation call create, update, delete, execute, publish, send या किसी अन्य तरीके से externally visible state बदलती है।
3. Ambiguous call को mutation की तरह संभालें, जब तक कोई इसके विपरीत साबित न कर दे।

तीसरी category को ज़्यादातर teams जितना महत्व देना चाहिए, उतना नहीं देतीं। अगर कोई endpoint के contract और controlled test के आधार पर उसके side effects समझा नहीं सकता, तो केवल उसका नाम harmless लगने के कारण उसे unattended discovery set में शामिल न करें।

## HTTP verbs संकेत देते हैं, permission decision नहीं

HTTP method names calls को classify करने में मदद करते हैं, लेकिन endpoint review की जगह नहीं ले सकते। RFC 9110 GET, HEAD, OPTIONS और TRACE को «safe» methods बताता है। इसका अर्थ है कि client state change का request नहीं करता। RFC यह भी चेतावनी देता है कि server फिर भी requests log कर सकता है, account से charge कर सकता है या दूसरे incidental effects पैदा कर सकता है।

यह फर्क आसानी से छूट जाता है। HTTP safety request की intended semantics बताती है, यह कोई cryptographic promise नहीं कि implementation ने कुछ भी नहीं बदला। RFC 9110 resource owner की जिम्मेदारी बताता है कि safe-method conventions का पालन करने वाले users के लिए unsafe actions से बचा जाए। अगर service इस convention को तोड़ती है, तो आपका agent इस promise को लागू नहीं कर सकता।

इन्हें अंतिम निर्णय के बजाय शुरुआती स्थिति मानें:

1. GET और HEAD आम तौर पर discovery candidate set में आते हैं। पहले query parameters और endpoint documentation की समीक्षा करें।
2. POST, PUT, PATCH और DELETE mutation set में आते हैं, जब तक किसी specific endpoint के documented और tested read behavior का प्रमाण न हो।
3. OPTIONS server capabilities inspect कर सकता है, लेकिन कुछ platforms account-specific details भी दिखाते हैं, जिनके लिए scope control चाहिए।
4. Webhook test, job preview, report export या search endpoint POST इस्तेमाल कर सकते हैं और फिर भी observational हो सकते हैं। सभी POST access देने के बजाय उनका verification करें।

उलटी गलती भी आम है। Developers सुविधा के लिए किसी link या GET route को action से जोड़ देते हैं। `/reports/monthly?refresh=true` जैसा URL महँगे report cache को फिर से बना सकता है। `?send=true` वाला GET endpoint notification भेज सकता है। API description के आधार पर काम करने वाला agent वही इस्तेमाल करेगा जो उसे मिला है। यह उम्मीद न करें कि model समझ जाएगा कि server designer ने HTTP semantics को नज़रअंदाज़ किया।

Endpoint documentation में «creates,» «initiates,» «refreshes,» «generates,» «sends,» «records,» «synchronizes» और «charges» जैसे शब्द देखें। ये verbs call को discovery से बाहर कर देने चाहिए, भले ही route GET इस्तेमाल करती हो। फिर disposable account पर endpoint test करें और before तथा after state की तुलना करें। इसमें job queues, notifications, usage counters और audit records भी शामिल करें।

HTTP response request को classify करने में भी मदद करता है। Job identifier, operation identifier या new resource URL लौटाने वाला response अक्सर बताता है कि remote service ने काम शुरू कर दिया है। 200 status code केवल यह साबित करता है कि server ने request handle की। यह साबित नहीं करता कि request observational थी।

## Allowlists लिखने से पहले resources और effects तय करें

Paths की allowlist बहुत मोटी होती है, अगर वह हर path के पीछे मौजूद resource और effect को नज़रअंदाज़ करे। एक छोटी action inventory बनाएँ, जिसमें लिखा हो कि agent क्या inspect कर सकता है, क्या propose कर सकता है और direct human decision के बिना उसे क्या कभी नहीं करना चाहिए।

हर external action के लिए इस तरह का record रखें। नाम महत्वपूर्ण नहीं हैं। Evidence महत्वपूर्ण है।

```text
Action: repository pull request list
Channel: HTTP
Target pattern: GET /repos/{owner}/{repo}/pulls
Class: discovery
Data returned: title, status, branch names, review metadata
Side-effect evidence: API reference defines this endpoint as a list operation
Scope limit: named repositories only
Review date: 2025-02-14

Action: repository merge pull request
Channel: HTTP
Target pattern: PUT /repos/{owner}/{repo}/pulls/{number}/merge
Class: mutation
Effect: changes merge state and source history
Required control: explicit approval for each call
```

Inventory teams को उस फैसले के लिए मजबूर करती है जिसे वे अक्सर अस्पष्ट छोड़ देती हैं: क्या agent को इस resource के बारे में जानने की permission है, या इसे बदलने की permission? ये अलग-अलग grants हैं। Ticketing system issue title और status discover करने दे सकता है, लेकिन comment bodies से रोक सकता है क्योंकि उनमें customer data हो सकता है। Cloud account narrowly scoped workload की listing दे सकता है, लेकिन account-wide identities और billing records तक access रोक सकता है।

Scope को action record में रखें। `GET /projects` उपयोगी permission description नहीं है, अगर credential company के बनाए हर project की listing कर सकता है। बेहतर description में वह organization, repository, namespace, account या path स्पष्ट होना चाहिए जिसकी agent को ज़रूरत है। अगर upstream service credential को इस तरह सीमित नहीं कर सकती, तो action gateway पर target allowlist लागू करें या discovery को automatic न बनाएँ।

इस list को केवल swagger files से न बनाएँ। API descriptions अक्सर method और parameters बताती हैं, लेकिन operational consequences छोड़ देती हैं। Documentation को test account, service के audit trail और remote system के maintainer के साथ मिलाकर देखें। लक्ष्य यह स्पष्ट claim बनाना है जिसे API बदलने पर कोई दोबारा जाँच सके।

## Read request भी system को नुकसान पहुँचा सकती है

Read access का भी blast radius होता है और इसकी अपनी limits होनी चाहिए। ऐसा agent जिसे हर repository, secret name, incident note, customer record और deployment event inspect करने की permission है, बहुत नुकसान कर सकता है अगर attacker agent process या उसकी instructions को control कर ले।

लोकप्रिय सलाह है, «पहले read-only access दें।» यह लोकप्रिय इसलिए है क्योंकि सावधान लगती है और familiar IAM role names से मेल खाती है। लेकिन जब यह data classification पर विचार करने के बजाय broad read role दे देती है, तब यह गलत है। Broad discovery अक्सर design में सबसे बड़ा information disclosure पैदा करती है।

दो सवाल अलग रखें:

- क्या request remote state बदल सकती है?
- क्या response ऐसी information दिखा सकती है जो agent को नहीं मिलनी चाहिए?

Request को discovery treatment तभी दें जब वह पहला सवाल clear कर ले। उसे कोई permission तभी दें जब वह दूसरा सवाल भी clear कर ले। इन दोनों tests को एक ही label में न मिलाएँ।

Sensitive resources के लिए केवल वही fields लौटाएँ जिनकी agent को ज़रूरत है। Deployment diagnosis के लिए pod phase, image digest और recent event messages पर्याप्त हो सकते हैं। Environment values या पूरा configuration object नहीं चाहिए। Issue triage agent को labels और timestamps की ज़रूरत हो सकती है, हर private comment की नहीं। अगर API field selection नहीं देती, तो उसके सामने narrow intermediary action रखें या operation को approval के पीछे रखें।

Pagination पर भी ध्यान दें। List endpoint happy-path test में bounded दिख सकता है, लेकिन जब agent cursors follow करे तो unbounded data extraction path बन सकता है। जहाँ channel अनुमति दे, page size और total pages की सीमा लगाएँ। इस cap को action inventory में दर्ज करें। Rate limits provider की सुरक्षा करती हैं, लेकिन वे आपके agent के लिए उचित information boundary तय नहीं करतीं।

Search endpoints के साथ भी यही सावधानी रखें। Source code या support records पर full-text search direct object lookup से कहीं अधिक उजागर कर सकती है, और prompt text query को प्रभावित कर सकता है। Searchable collections और query syntax को सीमित करें। केवल GET इस्तेमाल होने के कारण agent-created search expressions को सीधे powerful backend में न भेजें।

## जहाँ संभव हो, credentials को यह विभाजन लागू करना चाहिए

Inspection और action के बीच फर्क करने की सबसे सुरक्षित जगह remote service का authorization model है। Discovery के लिए approved resources पढ़ सकने वाला credential और workflow में ज़रूरी bounded mutation actions के लिए अलग credential इस्तेमाल करें।

यह setup एक सरल लेकिन गंभीर failure को सीमित करता है: malicious या confused agent ऐसा mutation endpoint खोज ले जिसे आपने deny करना भूल गए। अगर discovery credential write नहीं कर सकता, तो action layer उसे गलत classify करे तब भी endpoint call fail हो जाएगी। यह independent controls से मिलने वाली defense है, action inventory के प्रति लापरवाही का कारण नहीं।

कुछ services scopes, roles, project permissions या अलग machine identities से यह काम आसान बनाती हैं। कुछ केवल broad personal token देती हैं। जब provider के पास दूसरा विकल्प न हो, तो उपलब्ध सबसे narrow account और project boundary इस्तेमाल करें, फिर gateway में specific endpoints और target patterns लागू करें। केवल इसलिए autonomous agent को administrator का personal credential कभी न दें कि वह पहले से उपलब्ध है।

एक साफ setup में अक्सर तीन credential classes होती हैं:

1. Discovery credential, जिसे agent के inspect किए जा सकने वाले exact resources तक access हो।
2. Mutation credential, bounded writes के लिए, जिन पर फिर भी approval decision ज़रूरी हो।
3. Break-glass credential, जिसका agent कभी इस्तेमाल न करे और जिसे humans केवल incident process के ज़रिए प्राप्त करें।

Mutation credential को default रूप से discovery calls का जवाब न देने दें। यह harmless लगता है क्योंकि endpoint read-only है, लेकिन इससे future review कठिन हो जाती है। Powerful credential ने resource query किया, इतना लिखी हुई log यह नहीं बताती कि agent को उस authority की ज़रूरत थी या नहीं। Identity का अर्थ स्पष्ट रखें।

Sallyport API और SSH credentials को अपने encrypted vault में रखता है और outbound action खुद execute करता है, इसलिए MCP agent को secret के बजाय result मिलता है। इससे narrow discovery route expose करना व्यावहारिक हो जाता है, बिना bearer token या private SSH material को agent के context में रखे।

## Approval को change बताना चाहिए, हर request को दंडित नहीं करना चाहिए

Per-call approval तब काम करता है जब reviewer कोई concrete effect देख सके और जल्दी निर्णय ले सके। यह तब विफल होता है जब system हर harmless lookup के बाद consent माँगता है। Human सीख जाता है कि prompt में ऐसा कोई निर्णय नहीं है जिस पर ध्यान देना हो।

Session authorization से तय करें कि कौन-सा agent process discovery set इस्तेमाल कर सकता है। फिर mutation actions के लिए individual approval माँगें और request को ऐसे शब्दों में दिखाएँ जिन्हें human परख सके। «POST /v1/jobs» approval text के लिए खराब है। «Project northwind के लिए data export शुरू करें, destination archive bucket, अनुमानित अवधि 30 दिन» reviewer को जाँचने के लिए कुछ ठोस देता है।

Approval card में target, operation, meaningful parameters और credential identity शामिल होनी चाहिए। Target को लंबे JSON body में न छिपाएँ। अगर action एक से अधिक resources को छूती है, तो count और छोटा sample दिखाएँ। जब count सामान्य expected range से अधिक हो, approval से पहले operator को पूरी list खोलने दें।

Bounded update के लिए request payload इस तरह दिख सकती है:

```json
{
  "action": "update_issue",
  "target": {
    "repository": "payments-api",
    "issue": 1842
  },
  "changes": {
    "labels_add": ["needs-review"],
    "assignee": "release-manager"
  },
  "reason": "The release checklist is complete."
}
```

Agent अपनी permitted scope के भीतर unrestricted discovery के बाद यह request तैयार कर सकता है। Human को change approve करना चाहिए, agent की पूरी investigation दोबारा नहीं करनी चाहिए। Reason सुरक्षित रखें, क्योंकि इससे बाद की review में अनुमान कम लगते हैं। लेकिन reason को security control न मानें। Agent खराब target के लिए भी विश्वसनीय वाक्य बना सकता है।

Approval policies को केवल natural-language intent पर आधारित न करें। «Approve deployment changes» उचित लगता है, जब तक agent database deletion को deployment change के रूप में label न कर दे। Approval को operation class, target scope और credential से बाँधें। Text humans को request समझने में मदद करता है। Typed action boundaries mismatch रोकती हैं।

## Deletion और external execution की अपनी class होनी चाहिए

Deletion, permission changes, credential rotation, financial operations और external systems को trigger करने वाली calls को सामान्य updates से कड़े controls मिलने चाहिए। ये recovery paths हटा सकती हैं, access बदल सकती हैं, cost पैदा कर सकती हैं या उस system के बाहर काम शुरू कर सकती हैं जहाँ agent ने शुरुआत की थी।

Deletion को सामान्य mutation bucket में न छिपाएँ। Issue label ठीक करने वाला patch आम तौर पर आसानी से reverse किया जा सकता है। Delete call attachments, child records, history या named environment हटा सकती है। API success लौटाने के बाद asynchronous cleanup queue कर सकती है, इसलिए operator हमेशा एक compensating request से गलती नहीं सुधार सकता।

इन actions के लिए अलग per-call control ज़रूरी करें:

1. Delete, purge, archive जब archive availability बदलता हो, और bulk removal।
2. Permission, membership, role, secret, credential और access-policy changes।
3. Deployment, restart, scale, migration और remote command execution।
4. Email भेजना, messages post करना, external tickets खोलना और paid jobs शुरू करना।

Approval किसी व्यक्ति तक पहुँचने से पहले agent को identifiers को preview में resolve करने के लिए बाध्य करें। `records?filter=status=inactive` पर deletion request exact count, filter और representative names दिखाए। इससे भी बेहतर है कि agent पहले candidate identifiers प्राप्त करे और list submit करे, जिसे gateway execution request से compare करे। इससे race conditions पूरी तरह नहीं मिटतीं, लेकिन सबसे आम गलती पकड़ी जाती है: filter का अर्थ agent की धारणा से अलग होना।

Time-bound confirmation भी समझदारी है। अगर operator ने destructive request को एक घंटे पहले approve किया था, तो आसपास की state बदलने के बाद agent को उस approval का इस्तेमाल नहीं करना चाहिए। Approval को एक request body या immutable request digest से बाँधें, «आज access delete करें» जैसी broad category से नहीं।

## SSH के लिए command-level classification ज़रूरी है

SSH को अच्छी तरह design की गई API से classify करना कठिन है, क्योंकि command line inspection और mutation को मिला सकती है, shell चला सकती है, aliases follow कर सकती है या remote environment के आधार पर behavior बदल सकती है। पूरे host को read-only कहना सुरक्षित नहीं है, केवल इसलिए कि agent read command चलाना चाहता है।

Explicit commands और arguments से शुरुआत करें। `git status --short`, `git log -n 20 --oneline` और `kubectl get pods -n staging` plausible discovery actions हैं, अगर working directory, cluster context और namespace सीमित हों। `git push`, `kubectl apply`, `kubectl delete`, `rm`, package installation और service restarts mutation या destructive execution classes में आते हैं।

Unattended discovery के लिए shell composition को reject करें। यह command listing request जैसी दिखती है, लेकिन control shell को वापस दे देती है:

```sh
find "$WORKDIR" -maxdepth 2 -type f -name '*.log' -print; $EXTRA_COMMAND
```

Testing में agent चाहे `EXTRA_COMMAND` को empty दे, बाद में कोई value SSH identity को उपलब्ध हर action execute कर सकती है। ऐसी command grammar को approve न करें जिसमें `;`, `&&`, `||`, command substitution, redirects, uncontrolled paths पर wildcard expansion या interpreter invocation हो, जब तक action को execution की तरह review न किया गया हो।

इसके बजाय structured arguments इस्तेमाल करें। Gateway `list_recent_logs` नाम की action स्वीकार कर सकता है, fixed directory और numeric limit validate कर सकता है और फिर remote command खुद बना सकता है। जब typed action उपलब्ध हो, agent को shell string submit नहीं करनी चाहिए।

यही principle read verbs वाले tools पर भी लागू होता है। Resource और namespace broad हों तो `kubectl get` secret data leak कर सकता है। गलती से commit किया गया credential `git show` उजागर कर सकता है। Command permissions को executable, subcommand, arguments, working directory और remote identity के आधार पर बनाएँ। केवल verb से बहुत कम जानकारी मिलती है।

## Audit records में यह दिखना चाहिए कि boundary कायम रही

Audit trail से reviewer को पता चलना चाहिए कि call किसने की, action ने कौन-सा credential route इस्तेमाल किया, किस target तक पहुँची, क्या किसी human ने approval दिया और remote system ने क्या लौटाया। अगर trail केवल «agent invoked tool» रिकॉर्ड करती है, तो यह साबित नहीं कर सकती कि discovery access mutation authority से अलग रही।

Attempted और completed दोनों actions log करें। Denied delete request भी महत्वपूर्ण है। इससे पता चल सकता है कि agent ने scope गलत समझा, prompt injection ने उसे मोड़ने की कोशिश की या कोई boundary test कर रहा है। Denial reason रिकॉर्ड करें, लेकिन secrets या sensitive response bodies को ऐसे log में न लिखें जिसकी access original system से अधिक व्यापक हो।

हर action के लिए कम से कम ये fields tamper-evident record में रखें:

- Agent process identity और session identifier।
- Action class: discovery, mutation, destructive या external execution।
- Target identity, request method या command form और parameters का safe representation।
- Approval event, जिसमें आवश्यक होने पर approving human भी शामिल हो।
- Outcome, remote status, result reference और timestamps।

Hash chain log modification का पता लगाने में मदद करती है, लेकिन अस्पष्ट event को उपयोगी नहीं बनाती। Execution से पहले canonical action record store करें और response record को उससे bind करें। अगर record में केवल `POST /jobs` लिखा है, तो बाद का reviewer फिर भी यह नहीं जान पाएगा कि agent ने harmless report शुरू की या महँगा export।

Sallyport session और call journals को एक encrypted hash-chained audit log से project करता है, और `sp audit verify` vault access के बिना offline chain check करता है। Verification तभी उपयोगी है जब action taxonomy event को समझने योग्य बनाए। इसलिए classification को reporting layer में बाद में label करने के बजाय execution path के पास रखें।

## Boundary को happy paths से नहीं, failures से test करें

Permission split पर भरोसा तभी बनता है जब वह आपके अनुमानित bad requests को block करे। हर discovery action को testable contract मानें और API, command wrapper या agent workflow बदलने पर negative cases चलाएँ।

HTTP discovery route के लिए allowed target, पास का forbidden target, unsupported method, oversized page request और tenant या project boundary पार करने की कोशिश करने वाली query test करें। Specific denials की अपेक्षा रखें। Generic server error खराब evidence है, क्योंकि छोटे code change के बाद वही request सफल हो सकती है।

Mutation route के लिए test करें कि valid request approval पर रुके, किसी meaningful field को बदलने पर approval invalid हो जाए और दूसरा agent process पहले process की session permission inherit न करे। Deletion के लिए empty selectors, wildcard जैसे selectors, expected से बड़ी lists और preview तथा execution के बीच गायब हो चुके targets test करें।

हर action class के लिए एक worked trace रखें। अच्छी trace इतनी छोटी हो कि reviewer पढ़ सके और इतनी concrete हो कि mismatch सामने आ जाए:

```text
09:14:03  discovery  GET /projects/acme/services?limit=20  allowed
09:14:05  discovery  GET /projects/acme/services/api-7/events  allowed
09:14:11  mutation   POST /projects/acme/services/api-7/restart  approval required
09:14:32  mutation   POST /projects/acme/services/api-7/restart  approved by operator
09:14:34  mutation   result: accepted, operation=op_481
```

अगर तीसरी line की जगह `GET /services/api-7?action=restart` लिखा है, तो आपके classification model ने पहले ही defect खोज लिया है। Action contract ठीक करें या उस route को mutation control के पीछे रखें। Endpoint असुविधाजनक है, इसलिए exception न बनाएँ।

उन external actions से शुरुआत करें जिन्हें आपके agents पहले से perform करते हैं। हर action को effect के आधार पर mark करें, उसका actual behavior verify करें, target सीमित करें और denial cases test करें। जब agent कुछ नया करने की request करे, तो action production तक पहुँचने से पहले explicit classification ज़रूरी करें। यह छोटा pause बाद में unreviewed change को समझाने की कोशिश से कहीं सस्ता है।
