@guardbee/mcp-security-proxy 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/TR.md +17 -0
- package/ZH.md +17 -0
- package/dist/gateway/config.d.ts +3 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +2 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/gateway.d.ts +26 -3
- package/dist/gateway/gateway.d.ts.map +1 -1
- package/dist/gateway/gateway.js +152 -3
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/policy-sync.d.ts.map +1 -1
- package/dist/gateway/policy-sync.js +1 -0
- package/dist/gateway/policy-sync.js.map +1 -1
- package/dist/gateway/quota.d.ts +52 -0
- package/dist/gateway/quota.d.ts.map +1 -0
- package/dist/gateway/quota.js +76 -0
- package/dist/gateway/quota.js.map +1 -0
- package/dist/gateway/upstream.d.ts +27 -6
- package/dist/gateway/upstream.d.ts.map +1 -1
- package/dist/gateway/upstream.js +38 -11
- package/dist/gateway/upstream.js.map +1 -1
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +4 -0
- package/dist/http-server.js.map +1 -1
- package/dist/proxy.d.ts +2 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +15 -2
- package/dist/proxy.js.map +1 -1
- package/dist/tracing.d.ts +28 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +106 -0
- package/dist/tracing.js.map +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +24 -2
package/README.md
CHANGED
|
@@ -135,10 +135,12 @@ audit:
|
|
|
135
135
|
- **Tool exposure (`tools`):** `expose` is an allowlist of globs on the name the agent sees (absent: every tool), and `hide` removes tools after it. A hidden tool is left out of `tools/list`, so the model never reads its description (a smaller poisoning surface and fewer tokens), and a call to it is refused and counts toward `anomaly.repeatedBlocks`. `descriptions` replaces a tool's description with one you wrote; drift detection keeps watching the server's own. Unlike a `deny` rule, which refuses at call time, hiding takes the tool out of the agent's view.
|
|
136
136
|
- **Tool poisoning at `tools/list` (`interceptors.toolPoisoning`, on by default):** every definition is scanned before the agent sees it — the description (yours, when you wrote one under `tools.descriptions`), parameter descriptions and enum values in the input schema, and the read-only annotation. It catches instructions aimed at the model (`<IMPORTANT>`, "do not tell the user", "ignore previous instructions"), cross-tool shadowing ("when using the X tool, always…"), requests to read `.ssh`/`.env`, hidden zero-width, bidi and ANSI characters, words with Cyrillic or Greek lookalikes, and a `readOnlyHint` that the description contradicts. In `block` mode (default; follows `promptInjection.action` when unset) a tool with a critical or high finding is left out of the list and its calls are refused; medium findings (encoded blobs) only warn. Each finding is logged once as `ruleId: poisoning:<pattern>`. The rules are the ones `@guardbee/mcp-tool-poisoning-scanner` uses, now shared through guard-core.
|
|
137
137
|
- **Credentials leaving (`interceptors.egressSecrets`, on by default):** before an `egress` tool runs, the arguments it would actually receive are checked for credentials — provider keys (AWS, GitHub, OpenAI, Anthropic, Stripe, Slack, …), private keys and connection strings with a password; the same fixed-format rules PII masking uses, never the broad keyword ones. Data taint only knows what this session's tools returned; this also catches a key the model got from the prompt, a file or its own context. `block` (default; follows `promptInjection.action` when unset) refuses the call, `warn` logs it; the audit event has the credential masked either way. A PII token stays a token for an egress tool unless `piiMasking.detokenizeForEgress`, so only then is its value checked. `allowTools` exempts tools by glob (a deploy tool that takes a DB URL, say). Personal data is left to PII masking and taint.
|
|
138
|
+
- **Sampling (`interceptors.sampling`, off by default):** a server can ask the agent's model for a completion (`sampling/createMessage`) — and a malicious one can use that to smuggle instructions to the model or pull data out. Off, the proxy does not offer sampling to servers at all. On, a request is answered only while one of that server's tool calls is running, by the session that made the call (two sessions calling the same server at once: refused, since it could belong to either); `includeContext` is forced to `none`, so a server never gets the conversation; `maxTokens` is capped (default 1024) and so is the number of requests per call (`maxPerCall`, default 3); the system prompt and messages get the injection scan; `approval: true` asks the person first. The model's answer goes back to the server, so it is treated as egress: a credential or data this session saw blocks it, and personal data is masked. Events use `tool: sampling:<upstream>` and `ruleId: sampling:<check>`. The capability is offered when the proxy starts, so turning it on or off needs a restart.
|
|
138
139
|
- **Approval:** `approve` (a rule action, or `taint.mode: approve` for toxic flows) shows the person a yes/no form through MCP elicitation, with the tool, the reason and the arguments. Anything but an explicit yes — decline, cancel, no answer within `approval.timeoutSeconds` (default 120) — blocks the call. A client without elicitation support cannot approve, so the call is blocked with a message saying so.
|
|
139
140
|
- **Approval in the dashboard:** with `approval.channels: [elicitation, dashboard]` and `audit.dashboard` set, a client that cannot show a prompt no longer blocks the call outright. The request goes to the GuardBee dashboard (MCP Gateway page) with the arguments PII-masked, workspace owners and admins get a notification, and the proxy holds the call until someone approves or denies it there or `timeoutSeconds` passes. Channels are tried in order; the first one that can ask gives the answer.
|
|
140
141
|
- **Data-based taint (`taint.basis: data`):** the default `capability` basis blocks every egress call once a session holds untrusted and sensitive content. With `data`, the proxy keeps hashed fingerprints of what sensitive tools (and PII-bearing results) returned — personal data and credentials, id-like tokens, and runs of words — and treats an egress call as a toxic flow only when its arguments carry that data (12+ words in common, or an exact identifier; PII tokens count as their values) and the session also read untrusted content. The block message names the tool the data came from. Licence text, markdown boilerplate and text that also came back from ordinary results or from 3+ tools are ignored. Fingerprints are hashes, kept in memory per session. Trade-off: a paraphrase or a summary of the data is not caught; keep `capability` where that matters. In `capability` mode the same evidence is added to the block reason when found.
|
|
141
142
|
- **Anomaly checks (`interceptors.anomaly`):** behaviour no single call shows, counted per session over a sliding window. `callBurst` — more than 60 tool calls in 60s (a loop, or a denial-of-wallet). `sensitiveSweep` — more than 25 *different* reads of `sensitive` tools in 300s (enumerating a store record by record; re-reading the same record does not count). `destructiveBurst` — more than 5 `destructive` calls in 60s. `repeatedBlocks` — more than 5 calls blocked or declined in 300s (probing the policy; a client that cannot show an approval prompt does not count). Each takes `{ count, windowSeconds }`; the numbers above are the defaults. `warn` logs the first trip of each check; `block` refuses calls over the limit until the window slides, and after repeated blocks refuses every later call in the session. Events are `warn`/`blocked` with `ruleId: anomaly:<check>`, so the dashboard shows them without changes. Off unless configured.
|
|
143
|
+
- **Quotas (`quotas`):** caps on tool calls over a fixed window, counted across sessions — where `interceptors.anomaly` watches one session, a quota holds when a user opens ten. Each entry has `match` (`tool` and `user` globs, `upstream`, `label`, `group`; all optional), `limit`, `windowSeconds` and `per`: `user` (default; the OIDC user, or the session without one), `session`, or `gateway` (one budget for everyone, e.g. a paid upstream). Example: `quotas: [{ id: exports, match: { label: egress, group: contractors }, limit: 20, windowSeconds: 3600 }]`. Every matching quota is checked and a call counts against all of them or none; only calls that are about to reach the upstream count, so a call the policy refused does not spend quota. A full quota refuses the call with the time to retry, logs `ruleId: quota:<id>`, and does not count toward `anomaly.repeatedBlocks`. Counters live in the proxy process: several replicas each keep their own.
|
|
142
144
|
- **Policy from the dashboard:** `policy: { source: dashboard, refreshSeconds: 60 }` (with `audit.dashboard`) takes labels, rules, taint, approval, defaults and interceptors from the workspace policy edited in the GuardBee dashboard, instead of this file. Upstreams, listen and audit stay local. The proxy fetches it at start and re-checks it with an ETag; an update applies to the next call in every session (labels from the next `tools/list`). With no dashboard policy saved, the dashboard unreachable, or an invalid document, the proxy keeps the local or last good policy — it never runs without one.
|
|
143
145
|
- **Personal-data counts:** tool responses and resource reads that contained PII carry `piiHits`, a count per category (`tc_kimlik`, `vkn`, `iban`, `credit_card`, `email`, `phone_tr`; credentials as `secret`). Counts only, never the values, and counted even with masking off. The dashboard builds its KVKK report from them.
|
|
144
146
|
- **Tokenize:** with `interceptors.piiMasking.mode: tokenize` the model sees `<pii:tc_kimlik:7f3a9b21>` instead of the value and can still pass it to another tool: the proxy puts the real value back on the way to that server. Tokens live in memory for the session only, and are not turned back into values for an `egress` tool unless `piiMasking.detokenizeForEgress: true`.
|
|
@@ -152,6 +154,21 @@ The single-server `--` form above keeps its 0.x behavior: tool names are not pre
|
|
|
152
154
|
|
|
153
155
|
---
|
|
154
156
|
|
|
157
|
+
## Observability (OpenTelemetry)
|
|
158
|
+
|
|
159
|
+
Every tool call is a span named `tools/call <tool>` (kind SERVER) with the MCP semantic-convention attributes — `mcp.method.name`, `gen_ai.tool.name`, `gen_ai.operation.name: execute_tool`, `mcp.session.id`, `enduser.id` (OIDC) — plus `guardbee.upstream`, `guardbee.labels` and `guardbee.pii_hits`. The call to the upstream is a child span (kind CLIENT, `server.address` = upstream). Every audit event of the call — blocks, toxic flows, approvals, warnings, a server's sampling requests — is a span event (`guardbee.blocked`, … with `guardbee.rule_id` and `guardbee.reason`), and a blocked call carries `guardbee.blocked: true`. Arguments and results are never put on spans.
|
|
160
|
+
|
|
161
|
+
The proxy depends only on `@opentelemetry/api`, so without an SDK the spans cost nothing. To export over OTLP/HTTP, install the SDK next to the proxy and set the standard environment:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm i -g @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources
|
|
165
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.example.com:4318
|
|
166
|
+
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer …" # if your collector needs it
|
|
167
|
+
export OTEL_SERVICE_NAME=guardbee-gateway # default: guardbee-security-proxy
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The Docker image already has the SDK. `OTEL_SDK_DISABLED=true` or `OTEL_TRACES_EXPORTER=none` keeps it off, and a process that registered its own SDK first (zero-code instrumentation through `NODE_OPTIONS`) keeps that one.
|
|
171
|
+
|
|
155
172
|
## Remote Mode (HTTP)
|
|
156
173
|
|
|
157
174
|
The proxy can run as a shared network service instead of a subprocess of one client. Agents connect over Streamable HTTP, and upstreams can be remote Streamable HTTP servers too.
|
package/TR.md
CHANGED
|
@@ -135,10 +135,12 @@ audit:
|
|
|
135
135
|
- **Tool görünürlüğü (`tools`):** `expose`, ajanın gördüğü ad üzerinde glob'lardan oluşan bir beyaz listedir (yoksa tüm tool'lar), `hide` ondan sonra tool çıkarır. Gizli bir tool `tools/list`'te yer almaz, model açıklamasını hiç okumaz (daha küçük zehirleme yüzeyi, daha az token); çağrılırsa reddedilir ve `anomaly.repeatedBlocks` sayacına eklenir. `descriptions`, bir tool'un açıklamasını sizin yazdığınızla değiştirir; tanım değişikliği tespiti sunucunun kendi açıklamasını izlemeye devam eder. Çağrı anında reddeden `deny` kuralından farkı, tool'u ajanın görüş alanından tamamen çıkarmasıdır.
|
|
136
136
|
- **`tools/list` anında tool poisoning (`interceptors.toolPoisoning`, varsayılan açık):** her tanım ajan görmeden önce taranır — açıklama (`tools.descriptions` altında kendiniz yazdıysanız sizinki), input schema'daki parametre açıklamaları ve enum değerleri, ve read-only annotation. Modele yönelik talimatları (`<IMPORTANT>`, "kullanıcıya söyleme", "önceki talimatları yok say"), tool'lar arası shadowing'i ("X tool'unu kullanırken her zaman…"), `.ssh`/`.env` okuma isteklerini, gizli zero-width, bidi ve ANSI karakterlerini, Kiril veya Yunan benzeri harf içeren kelimeleri ve açıklamanın çeliştiği bir `readOnlyHint`'i yakalar. `block` modunda (varsayılan; ayarlanmazsa `promptInjection.action`'ı izler) critical veya high bulgusu olan tool listeden çıkarılır ve çağrıları reddedilir; medium bulgular (kodlanmış bloblar) sadece uyarır. Her bulgu bir kez `ruleId: poisoning:<kural>` ile loglanır. Kurallar `@guardbee/mcp-tool-poisoning-scanner`'ın kullandıklarıdır, artık guard-core üzerinden paylaşılır.
|
|
137
137
|
- **Dışarı çıkan kimlik bilgileri (`interceptors.egressSecrets`, varsayılan açık):** bir `egress` tool çalışmadan önce, gerçekten alacağı argümanlarda kimlik bilgisi aranır — sağlayıcı anahtarları (AWS, GitHub, OpenAI, Anthropic, Stripe, Slack, …), private key'ler ve şifre içeren bağlantı adresleri; PII maskelemenin kullandığı kesin formatlı kurallar, geniş anahtar-kelime kuralları asla. Veri bazlı taint sadece bu oturumdaki tool'ların döndürdüklerini bilir; bu kontrol modelin prompt'tan, bir dosyadan ya da kendi bağlamından aldığı bir anahtarı da yakalar. `block` (varsayılan; ayarlanmazsa `promptInjection.action`'ı izler) çağrıyı reddeder, `warn` loglar; audit event'inde kimlik bilgisi her iki durumda da maskelenir. Bir PII token'ı `piiMasking.detokenizeForEgress` açık değilse egress tool için token olarak kalır, değeri yalnızca o zaman kontrol edilir. `allowTools` tool'ları glob ile muaf tutar (ör. DB URL alan bir deploy tool'u). Kişisel veri PII maskeleme ve taint'e bırakılır.
|
|
138
|
+
- **Sampling (`interceptors.sampling`, varsayılan kapalı):** bir sunucu ajanın modelinden metin isteyebilir (`sampling/createMessage`) — kötü niyetli bir sunucu bunu modele talimat kaçırmak ya da veri çekmek için kullanabilir. Kapalıyken proxy sunuculara sampling'i hiç sunmaz. Açıkken bir istek yalnızca o sunucunun tool çağrılarından biri sürerken ve çağrıyı yapan oturum tarafından cevaplanır (iki oturum aynı sunucuyu aynı anda çağırıyorsa reddedilir, çünkü istek ikisine de ait olabilir); `includeContext` her zaman `none` yapılır, sunucu konuşmayı asla almaz; `maxTokens` (varsayılan 1024) ve çağrı başına istek sayısı (`maxPerCall`, varsayılan 3) sınırlanır; system prompt ve mesajlar injection taramasından geçer; `approval: true` önce kişiye sorar. Modelin cevabı sunucuya döndüğü için egress sayılır: bir kimlik bilgisi ya da oturumun gördüğü veri cevabı engeller, kişisel veri maskelenir. Event'ler `tool: sampling:<upstream>` ve `ruleId: sampling:<kontrol>` kullanır. Yetenek proxy başlarken sunulur; açıp kapatmak yeniden başlatma gerektirir.
|
|
138
139
|
- **Onay:** `approve` (kural aksiyonu olarak ya da toxic flow için `taint.mode: approve`) kişiye MCP elicitation üzerinden tool'u, gerekçeyi ve argümanları gösteren bir evet/hayır formu açar. Açık bir "evet" dışındaki her cevap (red, iptal, `approval.timeoutSeconds` içinde cevap gelmemesi; varsayılan 120) çağrıyı engeller. Elicitation desteklemeyen istemci onay veremez; çağrı bunu söyleyen bir mesajla engellenir.
|
|
139
140
|
- **Dashboard'dan onay:** `approval.channels: [elicitation, dashboard]` ve `audit.dashboard` ayarlıysa, onay formu gösteremeyen istemcide çağrı artık doğrudan engellenmez. İstek, argümanlardaki kişisel veriler maskelenmiş olarak GuardBee dashboard'una (MCP Gateway sayfası) gider; workspace sahipleri ve yöneticilerine bildirim düşer; proxy çağrıyı biri oradan onaylayana ya da reddedene veya `timeoutSeconds` dolana kadar bekletir. Kanallar sırayla denenir; soru sorabilen ilk kanal cevabı verir.
|
|
140
141
|
- **Veri bazlı taint (`taint.basis: data`):** varsayılan `capability`, oturum güvenilmeyen ve hassas içerik gördükten sonra her egress çağrısını engeller. `data` ile proxy, hassas tool'ların (ve PII içeren cevapların) döndürdüklerinin hash'lenmiş parmak izlerini tutar — kişisel veri ve kimlik bilgileri, id benzeri değerler ve kelime dizileri — ve bir egress çağrısını yalnızca argümanları bu veriyi taşıyorsa (12+ ortak kelime ya da birebir aynı tanımlayıcı; PII token'ları gerçek değerleri sayılır) ve oturum güvenilmeyen içerik de gördüyse toxic flow sayar. Engelleme mesajı verinin hangi tool'dan geldiğini söyler. Lisans metni, markdown kalıpları ve sıradan cevaplarda ya da 3+ tool'da tekrar eden metin yok sayılır. Parmak izleri hash'tir, oturum başına bellekte tutulur. Bedeli: verinin başka kelimelerle anlatılması veya özetlenmesi yakalanmaz; bunun önemli olduğu yerde `capability` kullanın. `capability` modunda da kanıt bulunursa engelleme gerekçesine eklenir.
|
|
141
142
|
- **Anomali kontrolleri (`interceptors.anomaly`):** tek bir çağrıda görünmeyen davranış, oturum başına kayan pencerede sayılır. `callBurst` — 60 saniyede 60'tan fazla tool çağrısı (döngüye giren ajan ya da denial-of-wallet). `sensitiveSweep` — 300 saniyede `sensitive` tool'lara 25'ten fazla *farklı* okuma (bir veri deposunu kayıt kayıt taramak; aynı kaydı tekrar okumak sayılmaz). `destructiveBurst` — 60 saniyede 5'ten fazla `destructive` çağrı. `repeatedBlocks` — 300 saniyede 5'ten fazla engellenen ya da reddedilen çağrı (politikayı yoklamak; onay penceresi gösteremeyen istemci sayılmaz). Her biri `{ count, windowSeconds }` alır; yukarıdaki sayılar varsayılandır. `warn` her kontrolün ilk tetiklenişini loglar; `block` pencere kayana kadar sınırı aşan çağrıları reddeder, tekrarlanan engellemelerden sonra da oturumdaki tüm sonraki çağrıları reddeder. Event'ler `ruleId: anomaly:<kontrol>` ile `warn`/`blocked` tipindedir, dashboard değişiklik gerekmeden gösterir. Ayarlanmadıkça kapalıdır.
|
|
143
|
+
- **Kotalar (`quotas`):** tool çağrılarına sabit bir pencerede, oturumlar arası sayılan sınırlar — `interceptors.anomaly` tek bir oturumu izlerken, kota bir kullanıcı on oturum açtığında da geçerlidir. Her kayıtta `match` (`tool` ve `user` glob, `upstream`, `label`, `group`; hepsi isteğe bağlı), `limit`, `windowSeconds` ve `per` vardır: `user` (varsayılan; OIDC kullanıcısı, yoksa oturum), `session` ya da `gateway` (herkes için tek bütçe, ör. ücretli bir upstream). Örnek: `quotas: [{ id: exports, match: { label: egress, group: contractors }, limit: 20, windowSeconds: 3600 }]`. Eşleşen her kota kontrol edilir ve çağrı ya hepsine ya hiçbirine sayılır; yalnızca upstream'e ulaşmak üzere olan çağrılar sayılır, policy'nin reddettiği çağrı kota harcamaz. Dolu bir kota çağrıyı tekrar deneme süresiyle reddeder, `ruleId: quota:<id>` loglar ve `anomaly.repeatedBlocks` sayacına eklenmez. Sayaçlar proxy process'inde tutulur: birden fazla kopya her biri kendi sayacını tutar.
|
|
142
144
|
- **Dashboard'dan politika:** `policy: { source: dashboard, refreshSeconds: 60 }` (`audit.dashboard` ile birlikte) etiketleri, kuralları, taint, onay, varsayılan aksiyon ve interceptor ayarlarını bu dosya yerine GuardBee dashboard'unda düzenlenen workspace politikasından alır. Upstream'ler, listen ve audit yerelde kalır. Proxy politikayı açılışta çeker ve ETag ile yeniden kontrol eder; güncelleme her oturumda bir sonraki çağrıda geçerli olur (etiketler bir sonraki `tools/list`'te). Dashboard'da kayıtlı politika yoksa, dashboard'a ulaşılamazsa ya da belge geçersizse proxy yerel ya da son geçerli politikayı korur — asla politikasız çalışmaz.
|
|
143
145
|
- **Kişisel veri sayıları:** PII içeren tool cevapları ve resource okumaları, kategori başına sayı tutan `piiHits` alanını taşır (`tc_kimlik`, `vkn`, `iban`, `credit_card`, `email`, `phone_tr`; kimlik bilgileri/anahtarlar `secret`). Yalnızca sayılar tutulur, değerler asla; maskeleme kapalıyken de sayılır. Dashboard'daki KVKK raporu bu sayılardan üretilir.
|
|
144
146
|
- **Tokenize:** `interceptors.piiMasking.mode: tokenize` ile model değerin yerine `<pii:tc_kimlik:7f3a9b21>` görür ve bu token'ı başka bir tool'a yine verebilir; proxy gerçek değeri o sunucuya giderken geri koyar. Token'lar sadece oturum boyunca bellekte tutulur ve `piiMasking.detokenizeForEgress: true` olmadıkça `egress` tool'lar için geri çevrilmez.
|
|
@@ -152,6 +154,21 @@ Yukarıdaki tek sunuculu `--` kullanımı 0.x davranışını korur: tool adlar
|
|
|
152
154
|
|
|
153
155
|
---
|
|
154
156
|
|
|
157
|
+
## Gözlemlenebilirlik (OpenTelemetry)
|
|
158
|
+
|
|
159
|
+
Her tool çağrısı `tools/call <tool>` adlı bir span'dır (kind SERVER) ve MCP semantik kurallarının özniteliklerini taşır — `mcp.method.name`, `gen_ai.tool.name`, `gen_ai.operation.name: execute_tool`, `mcp.session.id`, `enduser.id` (OIDC) — ayrıca `guardbee.upstream`, `guardbee.labels` ve `guardbee.pii_hits`. Upstream'e yapılan çağrı bir alt span'dır (kind CLIENT, `server.address` = upstream). Çağrının her audit olayı — engellemeler, toxic flow'lar, onaylar, uyarılar, sunucunun sampling istekleri — bir span event'idir (`guardbee.blocked`, … `guardbee.rule_id` ve `guardbee.reason` ile); engellenen çağrı `guardbee.blocked: true` taşır. Argümanlar ve sonuçlar span'lara asla yazılmaz.
|
|
160
|
+
|
|
161
|
+
Proxy yalnızca `@opentelemetry/api`'ye bağımlıdır; SDK yoksa span'ların maliyeti yoktur. OTLP/HTTP ile göndermek için SDK'yı proxy'nin yanına kurun ve standart ortam değişkenlerini ayarlayın:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm i -g @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources
|
|
165
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.example.com:4318
|
|
166
|
+
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer …" # collector'ınız istiyorsa
|
|
167
|
+
export OTEL_SERVICE_NAME=guardbee-gateway # varsayılan: guardbee-security-proxy
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Docker imajında SDK hazırdır. `OTEL_SDK_DISABLED=true` ya da `OTEL_TRACES_EXPORTER=none` kapalı tutar; kendi SDK'sını önce kaydeden bir process (`NODE_OPTIONS` ile zero-code enstrümantasyon) onu kullanmaya devam eder.
|
|
171
|
+
|
|
155
172
|
## Remote Mod (HTTP)
|
|
156
173
|
|
|
157
174
|
Proxy, tek bir istemcinin alt süreci olmak yerine paylaşılan bir ağ servisi olarak da çalışabilir. Ajanlar Streamable HTTP ile bağlanır; upstream'ler de uzak Streamable HTTP server'lar olabilir.
|
package/ZH.md
CHANGED
|
@@ -135,10 +135,12 @@ audit:
|
|
|
135
135
|
- **工具可见性(`tools`):** `expose` 是针对代理所见名称的 glob 白名单(未设置时为全部工具),`hide` 在其后移除工具。隐藏的工具不会出现在 `tools/list` 中,模型永远读不到它的描述(更小的投毒面、更少的 token);调用它会被拒绝,并计入 `anomaly.repeatedBlocks`。`descriptions` 用你编写的描述替换工具描述;定义漂移检测仍监视服务器自身的描述。与在调用时拒绝的 `deny` 规则不同,隐藏会把工具从代理的视野中完全移除。
|
|
136
136
|
- **`tools/list` 时的工具投毒检测(`interceptors.toolPoisoning`,默认开启):** 每个定义在代理看到之前都会被扫描——描述(如果你在 `tools.descriptions` 中编写了描述,则扫描你的)、输入 schema 中的参数描述和枚举值,以及只读注解。它能识别针对模型的指令(`<IMPORTANT>`、"不要告诉用户"、"忽略之前的指令")、跨工具影子攻击("使用 X 工具时,总是……")、读取 `.ssh`/`.env` 的请求、隐藏的零宽、bidi 和 ANSI 字符、含西里尔或希腊形近字母的单词,以及与描述相矛盾的 `readOnlyHint`。在 `block` 模式(默认;未设置时跟随 `promptInjection.action`)下,有 critical 或 high 发现的工具会从列表中移除,其调用会被拒绝;medium 发现(编码数据块)只发出警告。每个发现以 `ruleId: poisoning:<规则>` 记录一次。这些规则与 `@guardbee/mcp-tool-poisoning-scanner` 相同,现在通过 guard-core 共享。
|
|
137
137
|
- **外发凭据(`interceptors.egressSecrets`,默认开启):** 在 `egress` 工具运行前,检查它实际会收到的参数中是否有凭据——服务商密钥(AWS、GitHub、OpenAI、Anthropic、Stripe、Slack 等)、私钥以及带密码的连接字符串;使用与 PII 脱敏相同的固定格式规则,绝不使用宽泛的关键字规则。基于数据的污点追踪只知道本会话工具返回的内容;此检查还能发现模型从提示词、文件或自身上下文中得到的密钥。`block`(默认;未设置时跟随 `promptInjection.action`)拒绝调用,`warn` 记录日志;两种情况下审计事件中的凭据都会被脱敏。除非开启 `piiMasking.detokenizeForEgress`,PII 令牌对 egress 工具仍保持为令牌,只有此时才检查其值。`allowTools` 按 glob 豁免工具(例如接收数据库 URL 的部署工具)。个人数据交由 PII 脱敏和污点追踪处理。
|
|
138
|
+
- **采样(`interceptors.sampling`,默认关闭):** 服务器可以请求代理的模型生成内容(`sampling/createMessage`)——恶意服务器可借此向模型夹带指令或窃取数据。关闭时,代理根本不会向服务器提供采样能力。开启后,只有在该服务器的某个工具调用进行期间、由发起该调用的会话来响应请求(若两个会话同时调用同一服务器则拒绝,因为请求可能属于任一会话);`includeContext` 强制为 `none`,服务器永远拿不到对话内容;`maxTokens`(默认 1024)和每次调用的请求次数(`maxPerCall`,默认 3)均有上限;系统提示词和消息会经过注入扫描;`approval: true` 会先征求用户同意。模型的回答会返回给服务器,因此视为外发:包含凭据或本会话见过的数据会被拦截,个人数据会被脱敏。事件使用 `tool: sampling:<upstream>` 和 `ruleId: sampling:<检查>`。该能力在代理启动时提供,开启或关闭需要重启。
|
|
138
139
|
- **审批:** `approve`(规则动作,或针对有毒数据流的 `taint.mode: approve`)会通过 MCP elicitation 向用户展示一个是/否表单,其中包含工具、原因和参数。除明确的"是"之外的任何回答——拒绝、取消、在 `approval.timeoutSeconds`(默认 120 秒)内未作答——都会拦截该调用。不支持 elicitation 的客户端无法审批,调用会被拦截并附带说明。
|
|
139
140
|
- **在仪表盘中审批:** 设置 `approval.channels: [elicitation, dashboard]` 和 `audit.dashboard` 后,无法显示表单的客户端不会再直接拦截调用。请求会以 PII 已脱敏的参数发送到 GuardBee 仪表盘(MCP Gateway 页面),工作区所有者和管理员会收到通知;代理会一直保留该调用,直到有人在那里批准或拒绝,或 `timeoutSeconds` 到期。各渠道按顺序尝试,第一个能够发起询问的渠道给出答案。
|
|
140
141
|
- **基于数据的污点追踪(`taint.basis: data`):** 默认的 `capability` 模式在会话同时持有不可信内容和敏感内容后会拦截所有 egress 调用。使用 `data` 时,代理会保存敏感工具(以及含 PII 的结果)返回内容的哈希指纹——个人数据与凭据、类似 ID 的值以及词语序列——仅当 egress 调用的参数确实携带这些数据(至少 12 个相同的词,或完全相同的标识符;PII 令牌按其真实值计算)且会话也读取过不可信内容时,才视为有毒数据流。拦截信息会指出数据来自哪个工具。许可证文本、markdown 模板,以及在普通结果中或 3 个以上工具中重复出现的文本会被忽略。指纹仅为哈希,按会话保存在内存中。代价:对数据的改写或摘要无法被识别;在这一点重要的场景请保留 `capability`。在 `capability` 模式下,如发现证据也会写入拦截原因。
|
|
141
142
|
- **异常检测(`interceptors.anomaly`):** 单次调用看不出的行为,按会话在滑动窗口内计数。`callBurst` —— 60 秒内超过 60 次工具调用(陷入循环或 denial-of-wallet)。`sensitiveSweep` —— 300 秒内对 `sensitive` 工具超过 25 次*不同*的读取(逐条遍历数据存储;重复读取同一条记录不计数)。`destructiveBurst` —— 60 秒内超过 5 次 `destructive` 调用。`repeatedBlocks` —— 300 秒内超过 5 次被拦截或被拒绝的调用(试探策略;无法显示审批提示的客户端不计数)。每项接受 `{ count, windowSeconds }`;上述数字为默认值。`warn` 记录每项检查的首次触发;`block` 在窗口滑过之前拒绝超限调用,并在多次拦截后拒绝该会话之后的所有调用。事件类型为 `warn`/`blocked`,带 `ruleId: anomaly:<检查>`,仪表板无需改动即可显示。未配置时关闭。
|
|
143
|
+
- **配额(`quotas`):** 在固定时间窗口内对工具调用设置上限,并跨会话计数——`interceptors.anomaly` 只看单个会话,而配额在用户开十个会话时依然有效。每项包含 `match`(`tool` 和 `user` 支持 glob,`upstream`、`label`、`group`;均可选)、`limit`、`windowSeconds` 和 `per`:`user`(默认;OIDC 用户,没有时按会话)、`session` 或 `gateway`(所有人共享一个额度,例如付费上游)。示例:`quotas: [{ id: exports, match: { label: egress, group: contractors }, limit: 20, windowSeconds: 3600 }]`。所有匹配的配额都会检查,一次调用要么计入全部,要么都不计入;只有即将到达上游的调用才计数,被策略拒绝的调用不消耗配额。配额用尽时会拒绝调用并给出重试时间,记录 `ruleId: quota:<id>`,且不计入 `anomaly.repeatedBlocks`。计数器保存在代理进程中:多个副本各自计数。
|
|
142
144
|
- **来自仪表盘的策略:** `policy: { source: dashboard, refreshSeconds: 60 }`(需配合 `audit.dashboard`)会从 GuardBee 仪表盘中编辑的工作区策略获取标签、规则、污点、审批、默认动作和拦截器设置,而不是从本文件读取。上游、listen 和 audit 仍保留在本地。代理在启动时拉取策略,并用 ETag 重新检查;更新会在每个会话的下一次调用中生效(标签在下一次 `tools/list` 时生效)。如果仪表盘中尚未保存策略、仪表盘不可达或文档无效,代理会保留本地或最后一次有效的策略——绝不会在没有策略的情况下运行。
|
|
143
145
|
- **个人数据计数:** 含有 PII 的工具响应和资源读取会带有 `piiHits` 字段,按类别计数(`tc_kimlik`、`vkn`、`iban`、`credit_card`、`email`、`phone_tr`;凭据计为 `secret`)。只记录数量,从不记录值;即使关闭脱敏也会计数。仪表盘的 KVKK 报告基于这些计数生成。
|
|
144
146
|
- **令牌化(Tokenize):** 设置 `interceptors.piiMasking.mode: tokenize` 后,模型看到的是 `<pii:tc_kimlik:7f3a9b21>` 而不是真实值,并且仍然可以把它传给另一个工具:代理会在发往该服务器时把真实值放回去。令牌只在会话期间保存在内存中;除非设置 `piiMasking.detokenizeForEgress: true`,否则不会为 `egress` 工具还原成真实值。
|
|
@@ -152,6 +154,21 @@ audit:
|
|
|
152
154
|
|
|
153
155
|
---
|
|
154
156
|
|
|
157
|
+
## 可观测性(OpenTelemetry)
|
|
158
|
+
|
|
159
|
+
每次工具调用都是一个名为 `tools/call <tool>` 的 span(kind SERVER),带有 MCP 语义约定属性——`mcp.method.name`、`gen_ai.tool.name`、`gen_ai.operation.name: execute_tool`、`mcp.session.id`、`enduser.id`(OIDC)——以及 `guardbee.upstream`、`guardbee.labels` 和 `guardbee.pii_hits`。对上游的调用是一个子 span(kind CLIENT,`server.address` = 上游)。该调用的每个审计事件——拦截、有毒数据流、审批、警告、服务器的采样请求——都是一个 span 事件(`guardbee.blocked` 等,带 `guardbee.rule_id` 和 `guardbee.reason`),被拦截的调用带有 `guardbee.blocked: true`。参数和结果永远不会写入 span。
|
|
160
|
+
|
|
161
|
+
代理只依赖 `@opentelemetry/api`,没有 SDK 时 span 没有任何开销。要通过 OTLP/HTTP 导出,请在代理旁安装 SDK 并设置标准环境变量:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm i -g @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources
|
|
165
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.example.com:4318
|
|
166
|
+
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer …" # 如果收集器需要
|
|
167
|
+
export OTEL_SERVICE_NAME=guardbee-gateway # 默认:guardbee-security-proxy
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Docker 镜像已自带 SDK。`OTEL_SDK_DISABLED=true` 或 `OTEL_TRACES_EXPORTER=none` 可保持关闭;先注册了自己 SDK 的进程(通过 `NODE_OPTIONS` 的零代码插桩)会继续使用它。
|
|
171
|
+
|
|
155
172
|
## 远程模式(HTTP)
|
|
156
173
|
|
|
157
174
|
代理也可以作为共享的网络服务运行,而不只是某个客户端的子进程。智能体通过 Streamable HTTP 连接;上游也可以是远程的 Streamable HTTP 服务器。
|
package/dist/gateway/config.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AuditConfig, ProxyConfig, UpstreamConfig } from "../types.js";
|
|
|
2
2
|
import type { Label } from "./labels.js";
|
|
3
3
|
import type { PolicyAction, PolicyRule } from "./policy.js";
|
|
4
4
|
import type { OidcConfig } from "../auth.js";
|
|
5
|
+
import type { QuotaRule } from "./quota.js";
|
|
5
6
|
import type { TaintBasis, TaintMode } from "./taint.js";
|
|
6
7
|
import type { ApprovalChannel } from "./approval.js";
|
|
7
8
|
/** How the agent reaches the proxy. */
|
|
@@ -42,6 +43,8 @@ export interface GatewayConfig {
|
|
|
42
43
|
/** Which tools the agent sees (globs on the name it sees) and descriptions you wrote. */
|
|
43
44
|
tools: ToolExposure;
|
|
44
45
|
rules: PolicyRule[];
|
|
46
|
+
/** Call caps over a window, counted across sessions (see gateway/quota.ts). */
|
|
47
|
+
quotas: QuotaRule[];
|
|
45
48
|
taint: {
|
|
46
49
|
mode: TaintMode;
|
|
47
50
|
basis: TaintBasis;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAmB,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,uCAAuC;AACvC,MAAM,MAAM,YAAY,GACpB;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GACtB;IACE,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6FAA6F;IAC7F,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,4FAA4F;AAC5F,MAAM,MAAM,kBAAkB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvG,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,sGAAsG;IACtG,UAAU,EAAE,OAAO,CAAC;IACpB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAChC,yFAAyF;IACzF,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC;IAClE,QAAQ,EAAE;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,WAAW,CAAC;IACnB,YAAY,EAAE,WAAW,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;CACxD;AAiJD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAAwB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAmB,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,uCAAuC;AACvC,MAAM,MAAM,YAAY,GACpB;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,GACtB;IACE,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6FAA6F;IAC7F,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,4FAA4F;AAC5F,MAAM,MAAM,kBAAkB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvG,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,sGAAsG;IACtG,UAAU,EAAE,OAAO,CAAC;IACpB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAChC,yFAAyF;IACzF,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,+EAA+E;IAC/E,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC;IAClE,QAAQ,EAAE;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,WAAW,CAAC;IACnB,YAAY,EAAE,WAAW,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;CACxD;AAiJD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,SAAwB,GAAG,aAAa,CAiCjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAgBnE;AAgBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAM,EAAiB,EAAE,GAAG,GAAE,MAAsB,GAAG,aAAa,CAmB3G"}
|
package/dist/gateway/config.js
CHANGED
|
@@ -175,6 +175,7 @@ function parseGatewayYaml(source, fileLabel = "guardbee-proxy.yaml") {
|
|
|
175
175
|
labels: cfg.labels,
|
|
176
176
|
tools: cfg.tools,
|
|
177
177
|
rules: cfg.rules,
|
|
178
|
+
quotas: cfg.quotas,
|
|
178
179
|
taint: cfg.taint,
|
|
179
180
|
approval: cfg.approval,
|
|
180
181
|
defaults: cfg.defaults,
|
|
@@ -195,6 +196,7 @@ function fromLegacyConfig(config) {
|
|
|
195
196
|
labels: {},
|
|
196
197
|
tools: { hide: [], descriptions: {} },
|
|
197
198
|
rules: [],
|
|
199
|
+
quotas: [],
|
|
198
200
|
taint: { mode: "warn", basis: "capability" },
|
|
199
201
|
approval: { timeoutSeconds: 120, channels: ["elicitation"] },
|
|
200
202
|
defaults: { action: "allow" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type { CallToolResult, GetPromptResult, Prompt, ReadResourceResult, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
1
|
+
import type { CallToolResult, CreateMessageRequest, CreateMessageResult, GetPromptResult, Prompt, ReadResourceResult, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import type { AuditLogger } from "../audit/logger.js";
|
|
3
3
|
import type { Approver } from "./approval.js";
|
|
4
4
|
import type { GatewayConfig } from "./config.js";
|
|
5
5
|
import { DataFingerprints } from "./fingerprints.js";
|
|
6
|
+
import { QuotaStore } from "./quota.js";
|
|
6
7
|
import { TaintTracker } from "./taint.js";
|
|
7
8
|
import { PiiVault } from "./tokens.js";
|
|
8
9
|
import type { Upstream } from "./upstream.js";
|
|
10
|
+
/** The agent's client, for answering servers' sampling requests (see interceptors.sampling). */
|
|
11
|
+
export interface Sampler {
|
|
12
|
+
/** The client declared the sampling capability. */
|
|
13
|
+
available(): boolean;
|
|
14
|
+
create(params: CreateMessageRequest["params"]): Promise<CreateMessageResult>;
|
|
15
|
+
}
|
|
9
16
|
/** The person behind an HTTP session, from their OIDC token. */
|
|
10
17
|
export interface CallerIdentity {
|
|
11
18
|
user: string;
|
|
@@ -18,8 +25,9 @@ export interface CallerIdentity {
|
|
|
18
25
|
* tools/list scans each definition for poisoning before the agent sees it.
|
|
19
26
|
* A tool call runs: exposure / poisoning → session anomaly checks → input injection scan →
|
|
20
27
|
* definition drift → policy rules (incl. approval) → toxic-flow check →
|
|
21
|
-
* detokenize → credentials leaving → upstream → result injection scan → PII masking / tokenizing →
|
|
22
|
-
* field masking → taint update.
|
|
28
|
+
* detokenize → credentials leaving → quotas → upstream → result injection scan → PII masking / tokenizing →
|
|
29
|
+
* field masking → taint update. Sampling requests the server sends during the
|
|
30
|
+
* call are answered through sample().
|
|
23
31
|
*/
|
|
24
32
|
export declare class Gateway {
|
|
25
33
|
private readonly upstreams;
|
|
@@ -46,6 +54,9 @@ export declare class Gateway {
|
|
|
46
54
|
private readonly unsubscribers;
|
|
47
55
|
private readonly sessionId?;
|
|
48
56
|
private readonly identity?;
|
|
57
|
+
private readonly sampler?;
|
|
58
|
+
/** Shared by every session of the process over HTTP; this session's own over stdio. */
|
|
59
|
+
private readonly quotas;
|
|
49
60
|
/**
|
|
50
61
|
* One Gateway per agent session: taint, PII tokens and pins are per session.
|
|
51
62
|
* Over HTTP several sessions share the same upstream connections.
|
|
@@ -53,6 +64,8 @@ export declare class Gateway {
|
|
|
53
64
|
constructor(upstreams: readonly Upstream[], config: GatewayConfig, audit: AuditLogger, approver?: Approver | undefined, options?: {
|
|
54
65
|
sessionId?: string;
|
|
55
66
|
identity?: CallerIdentity;
|
|
67
|
+
sampler?: Sampler;
|
|
68
|
+
quotas?: QuotaStore;
|
|
56
69
|
now?: () => number;
|
|
57
70
|
});
|
|
58
71
|
/** Called when any upstream's tool list changed; proxy.ts relays it to the agent. */
|
|
@@ -82,7 +95,17 @@ export declare class Gateway {
|
|
|
82
95
|
*/
|
|
83
96
|
private protect;
|
|
84
97
|
listTools(): Promise<Tool[]>;
|
|
98
|
+
/** One span per call (MCP semantic conventions); the audit events of the call become its events. */
|
|
85
99
|
callTool(name: string, args: Record<string, unknown>): Promise<CallToolResult>;
|
|
100
|
+
private handleCall;
|
|
101
|
+
/** Lets the server ask for completions while this call runs, when interceptors.sampling is on. */
|
|
102
|
+
private samplingFor;
|
|
103
|
+
/**
|
|
104
|
+
* A server asking the agent's model for a completion. What it sends is
|
|
105
|
+
* untrusted text aimed at the model; what the model answers goes to the
|
|
106
|
+
* server, so it is checked like an egress call.
|
|
107
|
+
*/
|
|
108
|
+
private sample;
|
|
86
109
|
listResources(): Promise<Resource[]>;
|
|
87
110
|
/** Resource contents come from outside the agent's control: they taint the session like an untrusted tool. */
|
|
88
111
|
readResource(uri: string): Promise<ReadResourceResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway/gateway.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Gateway = void 0;
|
|
4
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
4
5
|
const guard_core_1 = require("@guardbee/guard-core");
|
|
5
6
|
const mcp_telemetry_1 = require("@guardbee/mcp-telemetry");
|
|
7
|
+
const api_1 = require("@opentelemetry/api");
|
|
8
|
+
const tracing_js_1 = require("../tracing.js");
|
|
6
9
|
const definition_drift_js_1 = require("../interceptors/definition-drift.js");
|
|
7
10
|
const anomaly_js_1 = require("./anomaly.js");
|
|
8
11
|
const fields_js_1 = require("./fields.js");
|
|
9
12
|
const labels_js_1 = require("./labels.js");
|
|
10
13
|
const fingerprints_js_1 = require("./fingerprints.js");
|
|
11
14
|
const policy_js_1 = require("./policy.js");
|
|
15
|
+
const quota_js_1 = require("./quota.js");
|
|
12
16
|
const taint_js_1 = require("./taint.js");
|
|
13
17
|
const tokens_js_1 = require("./tokens.js");
|
|
14
18
|
const SEPARATOR = "__";
|
|
@@ -31,8 +35,9 @@ function errorResult(text) {
|
|
|
31
35
|
* tools/list scans each definition for poisoning before the agent sees it.
|
|
32
36
|
* A tool call runs: exposure / poisoning → session anomaly checks → input injection scan →
|
|
33
37
|
* definition drift → policy rules (incl. approval) → toxic-flow check →
|
|
34
|
-
* detokenize → credentials leaving → upstream → result injection scan → PII masking / tokenizing →
|
|
35
|
-
* field masking → taint update.
|
|
38
|
+
* detokenize → credentials leaving → quotas → upstream → result injection scan → PII masking / tokenizing →
|
|
39
|
+
* field masking → taint update. Sampling requests the server sends during the
|
|
40
|
+
* call are answered through sample().
|
|
36
41
|
*/
|
|
37
42
|
class Gateway {
|
|
38
43
|
/**
|
|
@@ -59,8 +64,10 @@ class Gateway {
|
|
|
59
64
|
this.stale = new Set();
|
|
60
65
|
this.toolListeners = [];
|
|
61
66
|
this.unsubscribers = [];
|
|
67
|
+
this.quotas = options.quotas ?? new quota_js_1.QuotaStore(options.now);
|
|
62
68
|
this.sessionId = options.sessionId;
|
|
63
69
|
this.identity = options.identity;
|
|
70
|
+
this.sampler = options.sampler;
|
|
64
71
|
this.now = options.now;
|
|
65
72
|
for (const upstream of upstreams) {
|
|
66
73
|
const unsubscribe = upstream.onToolsChanged?.(() => {
|
|
@@ -105,6 +112,17 @@ class Gateway {
|
|
|
105
112
|
return pin;
|
|
106
113
|
}
|
|
107
114
|
log(event) {
|
|
115
|
+
// Inside a tool call, every audit event is also an event on its span
|
|
116
|
+
const span = (0, tracing_js_1.activeCallSpan)();
|
|
117
|
+
if (span) {
|
|
118
|
+
span.addEvent(`guardbee.${event.type}`, {
|
|
119
|
+
...(event.tool ? { "gen_ai.tool.name": event.tool } : {}),
|
|
120
|
+
...(event.ruleId ? { "guardbee.rule_id": event.ruleId } : {}),
|
|
121
|
+
...(event.reason ? { "guardbee.reason": event.reason } : {}),
|
|
122
|
+
});
|
|
123
|
+
if (event.type === "blocked" || event.type === "toxic_flow")
|
|
124
|
+
span.setAttribute(`guardbee.${event.type}`, true);
|
|
125
|
+
}
|
|
108
126
|
this.audit.log({
|
|
109
127
|
ts: new Date().toISOString(),
|
|
110
128
|
...(this.sessionId ? { sessionId: this.sessionId } : {}),
|
|
@@ -232,7 +250,34 @@ class Gateway {
|
|
|
232
250
|
}
|
|
233
251
|
return listed;
|
|
234
252
|
}
|
|
253
|
+
/** One span per call (MCP semantic conventions); the audit events of the call become its events. */
|
|
235
254
|
async callTool(name, args) {
|
|
255
|
+
const span = (0, tracing_js_1.tracer)().startSpan(`tools/call ${name}`, {
|
|
256
|
+
kind: api_1.SpanKind.SERVER,
|
|
257
|
+
attributes: {
|
|
258
|
+
"mcp.method.name": "tools/call",
|
|
259
|
+
"gen_ai.operation.name": "execute_tool",
|
|
260
|
+
"gen_ai.tool.name": name,
|
|
261
|
+
...(this.sessionId ? { "mcp.session.id": this.sessionId } : {}),
|
|
262
|
+
...(this.identity ? { "enduser.id": this.identity.user } : {}),
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
try {
|
|
266
|
+
const result = await (0, tracing_js_1.withCallSpan)(span, () => this.handleCall(name, args));
|
|
267
|
+
if (result.isError)
|
|
268
|
+
span.setAttribute("error.type", "tool_error");
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
span.recordException(err instanceof Error ? err : String(err));
|
|
273
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err instanceof Error ? err.message : String(err) });
|
|
274
|
+
throw err;
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
span.end();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async handleCall(name, args) {
|
|
236
281
|
const started = Date.now();
|
|
237
282
|
let route = this.tools.get(name);
|
|
238
283
|
if (!route) {
|
|
@@ -243,6 +288,7 @@ class Gateway {
|
|
|
243
288
|
return errorResult(`Unknown tool: ${name}`);
|
|
244
289
|
const { upstream, labels } = route;
|
|
245
290
|
const base = { tool: name, server: upstream.name, upstream: upstream.name, labels };
|
|
291
|
+
(0, tracing_js_1.activeCallSpan)()?.setAttributes({ "guardbee.upstream": upstream.name, "guardbee.labels": labels });
|
|
246
292
|
/** A refused call counts toward the repeated-blocks check. */
|
|
247
293
|
const countRefusal = () => {
|
|
248
294
|
const anomaly = this.anomaly?.observeBlocked(name);
|
|
@@ -397,9 +443,36 @@ class Gateway {
|
|
|
397
443
|
this.log({ ...base, type: "warn", ruleId: "egress:credential", input, reason });
|
|
398
444
|
}
|
|
399
445
|
}
|
|
446
|
+
// 5c. Quotas: only a call that is about to go out counts
|
|
447
|
+
if (this.config.quotas.length > 0) {
|
|
448
|
+
const over = this.quotas.take(this.config.quotas, {
|
|
449
|
+
tool: name,
|
|
450
|
+
upstream: upstream.name,
|
|
451
|
+
labels,
|
|
452
|
+
...(this.sessionId ? { sessionId: this.sessionId } : {}),
|
|
453
|
+
...(this.identity ? { user: this.identity.user, groups: this.identity.groups } : {}),
|
|
454
|
+
});
|
|
455
|
+
// A full quota is not probing: it does not count toward anomaly.repeatedBlocks
|
|
456
|
+
if (over)
|
|
457
|
+
return block(over.reason, { ruleId: `quota:${over.ruleId}` }, false);
|
|
458
|
+
}
|
|
400
459
|
// 6. Forward
|
|
401
460
|
this.log({ ...base, type: "tool_call", ruleId: decision.ruleId, input: args });
|
|
402
|
-
const
|
|
461
|
+
const parent = (0, tracing_js_1.activeCallSpan)();
|
|
462
|
+
const upstreamSpan = (0, tracing_js_1.tracer)().startSpan(`tools/call ${route.name}`, { kind: api_1.SpanKind.CLIENT, attributes: { "mcp.method.name": "tools/call", "gen_ai.tool.name": route.name, "server.address": upstream.name } }, parent ? api_1.trace.setSpan(api_1.context.active(), parent) : undefined);
|
|
463
|
+
let result;
|
|
464
|
+
try {
|
|
465
|
+
result = await upstream.callTool(route.name, forwardArgs, this.samplingFor(upstream, name));
|
|
466
|
+
if (result.isError)
|
|
467
|
+
upstreamSpan.setAttribute("error.type", "tool_error");
|
|
468
|
+
}
|
|
469
|
+
catch (err) {
|
|
470
|
+
upstreamSpan.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err instanceof Error ? err.message : String(err) });
|
|
471
|
+
throw err;
|
|
472
|
+
}
|
|
473
|
+
finally {
|
|
474
|
+
upstreamSpan.end();
|
|
475
|
+
}
|
|
403
476
|
// 7. Indirect injection in the result (text and structured)
|
|
404
477
|
let content = result.content;
|
|
405
478
|
if (this.interceptors.toolResultInjection?.enabled !== false) {
|
|
@@ -444,6 +517,8 @@ class Gateway {
|
|
|
444
517
|
else if (this.config.taint.basis === "data")
|
|
445
518
|
this.fingerprints.addOrdinary([result.content, result.structuredContent ?? null]);
|
|
446
519
|
this.log({ ...base, type: "tool_response", output: out.content, ...(piiFound ? { piiHits: hits } : {}) });
|
|
520
|
+
if (piiFound)
|
|
521
|
+
(0, tracing_js_1.activeCallSpan)()?.setAttribute("guardbee.pii_hits", Object.values(hits).reduce((sum, n) => sum + n, 0));
|
|
447
522
|
void (0, mcp_telemetry_1.recordEvent)({
|
|
448
523
|
server: "security-proxy",
|
|
449
524
|
tool: name,
|
|
@@ -453,6 +528,80 @@ class Gateway {
|
|
|
453
528
|
});
|
|
454
529
|
return out;
|
|
455
530
|
}
|
|
531
|
+
/** Lets the server ask for completions while this call runs, when interceptors.sampling is on. */
|
|
532
|
+
samplingFor(upstream, tool) {
|
|
533
|
+
if (!this.interceptors.sampling?.enabled)
|
|
534
|
+
return {};
|
|
535
|
+
let asked = 0;
|
|
536
|
+
// The server's request arrives on its own transport: tie it back to this call's span
|
|
537
|
+
const span = (0, tracing_js_1.activeCallSpan)();
|
|
538
|
+
const handler = (params) => span ? (0, tracing_js_1.withCallSpan)(span, () => this.sample(upstream, tool, params, ++asked)) : this.sample(upstream, tool, params, ++asked);
|
|
539
|
+
return { sampling: { owner: this, handler } };
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* A server asking the agent's model for a completion. What it sends is
|
|
543
|
+
* untrusted text aimed at the model; what the model answers goes to the
|
|
544
|
+
* server, so it is checked like an egress call.
|
|
545
|
+
*/
|
|
546
|
+
async sample(upstream, tool, params, nth) {
|
|
547
|
+
const config = this.interceptors.sampling;
|
|
548
|
+
const source = `sampling:${upstream.name}`;
|
|
549
|
+
const base = { tool: source, server: upstream.name, upstream: upstream.name };
|
|
550
|
+
const refuse = (reason, ruleId) => {
|
|
551
|
+
this.log({ ...base, type: "blocked", ruleId, reason });
|
|
552
|
+
this.anomaly?.observeBlocked(source);
|
|
553
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `${PREFIX} Sampling refused: ${reason}`);
|
|
554
|
+
};
|
|
555
|
+
if (!config?.enabled)
|
|
556
|
+
return refuse("interceptors.sampling is off", "sampling:off");
|
|
557
|
+
if (!this.sampler?.available())
|
|
558
|
+
return refuse("the agent's client does not support sampling", "sampling:unavailable");
|
|
559
|
+
const maxPerCall = config.maxPerCall ?? 3;
|
|
560
|
+
if (nth > maxPerCall)
|
|
561
|
+
return refuse(`more than ${maxPerCall} sampling requests during one call of "${tool}"`, "sampling:per_call");
|
|
562
|
+
// What the server puts in front of the model
|
|
563
|
+
const scan = (0, guard_core_1.scanToolResult)([params.systemPrompt ?? "", params.messages], config.action);
|
|
564
|
+
if (scan.action === "block")
|
|
565
|
+
return refuse(scan.reason, "sampling:injection");
|
|
566
|
+
if (scan.action === "warn")
|
|
567
|
+
this.log({ ...base, type: "warn", ruleId: "sampling:injection", reason: scan.reason });
|
|
568
|
+
if (config.approval) {
|
|
569
|
+
const outcome = this.approver
|
|
570
|
+
? await this.approver({
|
|
571
|
+
tool: source,
|
|
572
|
+
upstream: upstream.name,
|
|
573
|
+
args: { systemPrompt: params.systemPrompt ?? null, messages: params.messages },
|
|
574
|
+
reason: `"${upstream.name}" asks your model for a completion during "${tool}"`,
|
|
575
|
+
...(this.sessionId ? { sessionId: this.sessionId } : {}),
|
|
576
|
+
})
|
|
577
|
+
: "unavailable";
|
|
578
|
+
this.log({ ...base, type: "approval", reason: `${outcome}: sampling during "${tool}"` });
|
|
579
|
+
if (outcome !== "approved")
|
|
580
|
+
return refuse(`not approved (${outcome})`, "sampling:approval");
|
|
581
|
+
}
|
|
582
|
+
// No conversation context for the server, and a bounded completion
|
|
583
|
+
if (params.includeContext && params.includeContext !== "none") {
|
|
584
|
+
this.log({ ...base, type: "warn", ruleId: "sampling:context", reason: `includeContext "${params.includeContext}" reduced to "none": a server gets no conversation context` });
|
|
585
|
+
}
|
|
586
|
+
const request = { ...params, includeContext: "none", maxTokens: Math.min(params.maxTokens, config.maxTokens ?? 1024) };
|
|
587
|
+
this.log({ ...base, type: "tool_call", reason: `sampling during "${tool}" (${nth}/${maxPerCall})`, input: { systemPrompt: request.systemPrompt ?? null, messages: request.messages } });
|
|
588
|
+
const result = await this.sampler.create(request);
|
|
589
|
+
// The answer goes to the server: no credentials, no data this session saw
|
|
590
|
+
const credentials = this.credentialsIn(result.content);
|
|
591
|
+
const carried = this.fingerprints.find(this.vault.detokenize(result.content));
|
|
592
|
+
const leak = credentials.length > 0
|
|
593
|
+
? `the model's answer holds a credential (${credentials.join(", ")})`
|
|
594
|
+
: carried
|
|
595
|
+
? `the model's answer carries data from "${carried.source}"`
|
|
596
|
+
: null;
|
|
597
|
+
if (leak && config.action === "block")
|
|
598
|
+
return refuse(`${leak}; it would go to "${upstream.name}"`, "sampling:egress");
|
|
599
|
+
if (leak)
|
|
600
|
+
this.log({ ...base, type: "warn", ruleId: "sampling:egress", reason: leak });
|
|
601
|
+
const masked = this.protect(result.content, true);
|
|
602
|
+
this.log({ ...base, type: "tool_response", output: masked.value, ...(masked.piiFound ? { piiHits: masked.hits } : {}) });
|
|
603
|
+
return { ...result, content: masked.value };
|
|
604
|
+
}
|
|
456
605
|
async listResources() {
|
|
457
606
|
const listed = [];
|
|
458
607
|
for (const upstream of this.upstreams) {
|