BoundBench

Semantic Kernel

Microsoft SDK for integrating LLMs with plugins/function calling (C#, Python, Java)

github.com/microsoft/semantic-kernel · 2026-10-05 · 9974625

Defense-in-depth score

2.7 / 10

Minimal

With its defaults, Semantic Kernel's agent calls any registered tool the model asks for, without approval, and feeds tool results back unmarked, so a prompt-injected agent can use the developer's credentials and outbound tools unattended. Bundled plugins are carefully written (deny-by-default HTTP allowlist, encoded OpenAPI paths, a remote code sandbox), but there is no approval gate, no budget beyond five tool rounds, and settings are read from a .env in the working directory. Logging and telemetry are off unless the developer sets them up.

Key gaps (2)

  1. By default the agent auto-invokes every registered tool with no approval, and tool/MCP results enter the conversation unmarked, so a hijacked agent can exfiltrate and act irreversibly without a human. C5 · Untrusted input blast radius
  2. Settings classes read a .env file from the working directory by default, so that directory can set the model endpoint or enable sensitive telemetry without a trust decision. C6 · Memory, context & configuration integrity

Criteria

C1 Identity & least privilege

Minimal 0.05 / 1.00

Semantic Kernel runs every tool with whatever credentials the developer gives the AI service connector or the tool itself, usually long-lived API keys read from the environment. The framework has no way to scope a credential per tool, exchange tokens per request, or check authority before a tool runs. MCP servers launched over stdio receive only the MCP library's default minimal environment unless the developer passes one, which limits what those processes inherit.

C2 Approval gates

Minimal 0.15 / 1.00

The default ChatCompletionAgent advertises every registered function and runs whatever the model calls, up to five rounds, with no human approval step. The framework offers function-invocation filters, a hook where developers can write their own approval logic, but ships no approval gate for kernel functions. The one built-in approval path covers MCP tools hosted by the Azure AI Foundry Agent Service: when that service asks, a developer callback sees the exact tool name and arguments and the call is denied if no callback is set. That path is narrow and depends on the developer enabling approval on the service side.

C3 Tool & action scoping

Moderate 0.50 / 1.00

Every model-requested call is checked against the function's declared parameters: unknown or missing arguments are rejected and values are coerced into the declared Python or Pydantic types before the function runs. Bundled plugins are mostly careful: the HTTP plugin denies every host unless an allowlist is configured and disables redirects when one is, and OpenAPI path parameters are encoded and dot-segments rejected. The default agent has no tools until the developer adds some. Gaps: there is no central argument-policy layer, MCP servers can change their tool list at runtime and the new tools are loaded automatically, and the code-interpreter plugin's download function writes to any local path the model names unless download directories are configured.

C4 Code-execution isolation

Minimal 0.47 / 1.00

The core library does not run model-written code locally. The bundled code tool, SessionsPythonTool, sends code to Azure Container Apps dynamic sessions, a remote sandbox service, but it is opt-in. Configured stdio MCP servers and the developer's own plugins run on the host as ordinary processes or in-process code. Files the model downloads from the remote session can be written to any local path unless the developer restricts download directories.

C5 Untrusted input blast radius

Minimal 0.25 / 1.00

Tool and MCP results are appended to the conversation as ordinary tool messages with nothing marking them as untrusted, and the default agent then lets the model call any registered tool again without a human. The framework's prompt templates HTML-encode variable values and function output by default, which stops injected text from forging chat roles inside templates, but that is a formatting defense and does not cover tool results in the function-calling loop. A hijacked agent can therefore combine untrusted input, the developer's data and credentials, and outbound tools unattended.

C6 Memory, context & configuration integrity

Minimal 0.05 / 1.00

Every settings class, including the AI service connectors and the telemetry settings, reads a .env file from the process's working directory by default, filling any value not already set in the environment. A .env in the directory the app is started from can therefore set the model endpoint or turn on sensitive telemetry without any trust decision. The opt-in text memory plugin lets the model save anything into a collection it names, and recalled memories return as plain context with no provenance, review, or per-user namespace.

C7 Third-party extensions

Minimal 0.28 / 1.00

Third-party code enters through MCP servers, OpenAPI plugins, native plugin directories and Hugging Face models, all configured by the developer in code; nothing is enabled by default and no workspace file adds extensions. There is no pinning or integrity check, and when an MCP server announces a changed tool list the plugin reloads it silently. Stdio MCP servers run as separate processes with the MCP library's minimal default environment unless the developer passes one.

C8 Secrets & sensitive-data protection

Minimal 0.33 / 1.00

API keys are held as Pydantic SecretStr values, and OpenTelemetry capture of prompts, arguments and results is off by default. Tool-call arguments are logged at INFO level, and the full text of tool exceptions is returned to the model, with no masking on either path. A version header is added to outbound requests unless AZURE_TELEMETRY_DISABLED is set. Keys are typically long-lived.

C9 Audit & traceability

Minimal 0.35 / 1.00

Every kernel function invocation, including MCP and OpenAPI tools, runs inside an OpenTelemetry execute_tool span with the tool name, call id and timing; arguments and results are attached only when sensitive diagnostics are enabled. Nothing is recorded anywhere unless the developer configures an exporter, and there is no actor attribution or tamper-evident storage.

C10 Limits & kill switch

Minimal 0.30 / 1.00

The function-calling loop stops after five rounds by default, but each round can run any number of tool calls in parallel, and there is no token, cost or wall-clock budget. Tool calls have no framework timeout and MCP requests have none unless the developer sets one. Group chats default to 99 iterations and orchestration group chats have no round limit; cancelling an orchestration stops new messages but lets in-flight work finish.