SafetyCard Request a review

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

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.

Safest setup

Semantic Kernel starts an agent with no tools, checks every call against the function's declared parameters, and its bundled HTTP plugin blocks every host until you list one. As shipped the agent runs any registered tool the model asks for with no approval and no record, so the safest setup adds an approval filter, narrows tools and keys, and builds containment around the process.

SetupHowWhat it gives you
Scoped, low-limit keysGive the process only the model and tool keys this agent needs, each scoped or read-only with a spending limit set at the providerWhatever a tool call does, it reaches only the systems and spend you chose C1
Per-call approvalRegister an auto_function_invocation filter with add_filter that asks a person before consequential functions runA person sees each consequential tool call before it runs C2
Only the tools neededList the needed functions in included_functions under filters, and give HttpPlugin only the hosts it needs in allowed_domainsThe model can call only the functions and reach only the hosts the task uses C3
A remote code sandboxRun model-written code through SessionsPythonTool with allowed_download_directories setThat code runs in a remote session away from your host, and its files land only where you chose C4
A clean working directoryStart the app from a directory with no .env file you didn't writeSettings such as the model endpoint and telemetry come only from you C6
Round and time limitsKeep maximum_auto_invoke_attempts at its default of 5 or lower, and set request_timeout on MCP pluginsEach request ends after a few tool rounds, and a stuck MCP call ends on its own C10
Its own container or VMRun the app in a container or VM whose network reaches only the hosts the task needsAn outer boundary around in-process plugins and stdio MCP servers, and a narrow path for data to leave C5
Tool-call tracesSet SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS to true and configure an OpenTelemetry exporter to storage the app can't modifyA record of every tool call, with name, call id and timing C9

Approving with confidence

  • Read each prompt and approve calls one at a time; a filter can let read-only functions through and hold the rest for a person.
  • On AzureAIAgent, hosted MCP tools registered with approval required go to your mcp_tool_approval_callback, which sees the exact tool name and arguments.

Handling data

  • Tool-call arguments are logged at INFO level, so store application logs like the data the agent handles.
  • SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE adds prompts, arguments and results to traces; leave it off unless the trace store is protected like that data.

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

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

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

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

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

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

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

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

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

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

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.