A Semantic Kernel application lets a model choose and call your code, so every plugin function, every credential behind it and every filter around it is part of your security boundary. Semantic Kernel (SK) is Microsoft's open source SDK for .NET, Python and Java that wires AI services, prompt templates and plugins into a Kernel, and much production agent code still runs on it. This guide covers the SK-specific controls: which functions the model can see, how plugins get their credentials, the three filter types and how to use them as policy points, prompt template encoding, telemetry that can leak prompts, and how to plan the move to Microsoft Agent Framework, which Microsoft now describes as SK's successor. It is for developers, platform engineers and security reviewers of SK workloads. For the framework-neutral threat model see the Securing Agent Frameworks Guide; for the successor platform see the Microsoft Agent Framework and AutoGen security guide.
This is an independent guide from NHI Mgmt Group, based on Microsoft's public Semantic Kernel documentation as of November 2026. It is not sponsored or reviewed by Microsoft. Product features change, so confirm settings against Microsoft's current documentation.
Key takeaways
- Advertise only the functions a task needs. By default every function from every plugin registered on the Kernel is offered to the model; pass an explicit function list (.NET) or included_plugins and included_functions filters (Python) instead.
- Keep identity and secrets out of model-supplied arguments. Microsoft's plugin guidance is for the host to supply user and authentication context, and for OpenAPI plugins to add credentials in an AuthCallback that runs before each request.
- Use filters as your enforcement layer. A function invocation or auto function invocation filter that does not call next stops the call, which makes filters the place for allowlists, argument checks and approval gates.
- Leave prompt template encoding on. SK treats inserted variables and function return values as unsafe and HTML encodes them by default; every AllowUnsafeContent = true is a trust decision to review.
- Plan the Agent Framework move now. Microsoft has committed to critical bug and security fixes for SK v1.x for at least one year after Agent Framework general availability, with most new features going to Agent Framework.
Status: what Microsoft has said about Semantic Kernel
The SK GitHub repository now opens with "Semantic Kernel is now Microsoft Agent Framework!" and calls Agent Framework "the enterprise-ready successor to Semantic Kernel", noting that Agent Framework is available at version 1.0 as a production-ready release. In its October 2025 announcement, Microsoft said it would keep addressing critical bugs and security issues in SK, take some existing SK features to general availability, build the majority of new features for Agent Framework, and support SK v1.x for at least one year after Agent Framework leaves preview and is generally available.
| Question | Position as published (checked November 2026) | What it means for security owners |
|---|---|---|
| Will SK get security fixes? | Yes: critical bugs and security issues continue to be addressed for SK v1.x | Keep SK packages current and watch the repository's security policy (SECURITY.md) |
| Where do new features go? | Mostly to Agent Framework | New security features (for example newer approval and tool controls) may appear only in Agent Framework |
| How long is SK v1.x supported? | At least one year after Agent Framework general availability, and "for the foreseeable future" | Record a migration target date in your risk register; treat the published window as a minimum |
| Is there a bridge? | Yes: SK functions can be exposed to Agent Framework with as_agent_framework_tool, which needs semantic-kernel 1.38 or later | Lets you migrate agents first and plugins later, with both stacks patched |
SK's own agent APIs also changed during their move to release candidate: the .NET common agent invocation API arrived in 1.43.0 and Python 1.26.1 introduced breaking changes, with deprecated .NET patterns marked [Obsolete]. If your build suppresses obsolete warning CS0618, you may be hiding the very warnings that show which code paths need attention before migration. In NIST SP 800-53 terms, an SDK on a published support window is an SA-22 Unsupported System Components question once that window closes.
Plugins: what the model can call
SK imports plugins three ways: native code (methods marked with the KernelFunction attribute in C#, the kernel_function decorator in Python, DefineKernelFunction in Java), an OpenAPI specification, or an MCP server. SK can also expose a Kernel's plugins as an MCP server for other applications. Each route has a different trust profile.
| Plugin source | Runs where | Main risk | Controls |
|---|---|---|---|
| Native code | In your process, with your process identity | A function with broad side effects (file, shell, database writes) called on a prompt-injected instruction | Narrow function scope, parameter validation in code, function invocation filter, approval for writes |
| OpenAPI | Remote API, called by SK's HTTP layer | Every operation in the spec becomes a callable function; credentials attached to calls the model chose | Import only needed operations or specs, AuthCallback per operation, ServerUrlOverride to a known host, HTTPS only |
| MCP server (consumed) | Local process or remote server | Third-party tool descriptions and results flow into the model context; tool sets can change | Pin and review servers, restrict functions advertised, filters on every call; see the MCP Security Guide |
| Kernel exposed as MCP server | Your plugins offered to other clients | Your functions become callable by clients you do not control | Authenticate the MCP endpoint, expose a reduced plugin set, log every call |
Restrict what is advertised
Microsoft's function choice documentation states that, by default, all functions from plugins registered on the Kernel are provided to the AI model. That default is convenient in samples and risky in an application that registers an admin plugin next to a search plugin.
- .NET: pass the allowed functions explicitly, for example FunctionChoiceBehavior.Auto(functions: [...]). An empty list provides no functions, which is equivalent to disabling function calling.
- Python: pass filters to FunctionChoiceBehavior.Auto or Required with included_plugins, excluded_plugins, included_functions or excluded_functions. Microsoft notes that an empty included list has no effect; to disable function calling use FunctionChoiceBehavior.NoneInvoke().
- Concurrency: AllowConcurrentInvocation defaults to false in FunctionChoiceBehaviorOptions. Keep it off for functions with side effects, so filters and approvals see one call at a time.
- Function count: the plugin documentation quotes OpenAI's recommendation of no more than 20 tools per call, ideally no more than 10, and advises importing only the plugins a scenario needs. Fewer functions means fewer miscalls and a smaller attack surface.
Design functions so the model cannot widen them
- Host-supplied context: for functions that act on behalf of the current user or need authentication information, Microsoft describes transforming the function so the host application supplies that context and the model supplies only the remaining arguments. The user ID, tenant and token should never be parameters the model can fill.
- Local state for confidential data: the documentation recommends returning a state ID and keeping the original data locally, so large or confidential results are not sent to the model.
- Human approval: the plugin guidance says task automation functions will likely need human-in-the-loop approval. See the Human-in-the-Loop for AI Agents Guide.
Credentials: model services and plugins
An SK application usually holds two kinds of credential: one for the AI service and one or more for the systems its plugins reach. Both are non-human identities and both outlive any single conversation.
| Credential | How SK takes it | Recommended practice |
|---|---|---|
| Azure OpenAI or OpenAI key | apiKey (.NET) or api_key (Python) on the connector, or environment variables or a .env file | Prefer Microsoft Entra authentication; the Python AzureChatCompletion service attempts Entra token authentication when no API key is provided. Keep keys out of source and .env files in images |
| Process identity for native plugins | Whatever the host process runs as | A dedicated managed identity or service account per SK workload, with roles sized to the plugins it hosts. See the Azure Managed Identities Security Guide |
| OpenAPI plugin API credentials | AuthCallback on OpenApiFunctionExecutionParameters, invoked before each API request with access to the outgoing HTTP request | Fetch short-lived tokens in the callback from a secret store or token service; select scheme per operation from its security requirements metadata |
| Per-user delegated tokens | Host-supplied context passed to the function | Obtain on behalf of the signed-in user and pass by the host, never through model arguments or prompts |
| MCP server credentials | Transport configuration of the MCP connection | Separate credential per server, scoped to that server's tools |
- AuthCallback hygiene: Microsoft's sample comments advise storing sensitive values in environment variables or secure configuration, avoiding hard-coding, rotating and revoking unused tokens and keys, and using HTTPS. Add one more: if an API accepts keys in a query parameter, prefer a header, because query strings end up in proxy and server logs.
- Pin the host: ServerUrlOverride replaces both the server URL in the OpenAPI document and the URL the document was loaded from. Use it to point every call at a host you control or trust, rather than a server field in a spec you downloaded.
- Load specs from a reviewed copy: an OpenAPI document fetched at start-up from a remote URL can change the function set without a code change. Vendor the spec into your repository and review diffs. See the OpenAPI Specification Security Guide.
- Keep secrets out of prompts: never place keys or tokens in system messages or prompt variables, where they can be echoed or logged. See Secrets in Prompts.
- Agent Framework parity: the Agent Framework migration guide recommends a specific credential such as ManagedIdentityCredential in production rather than DefaultAzureCredential, and binding secrets and connections through the tool's enclosing class instance so the model never supplies them. The same patterns apply in SK today.
Filters as policy enforcement points
SK has three filter types. Each receives a context and a next delegate; Microsoft's documentation states that without calling next the operation will not be executed. That is the hook for enforcement.
| Filter | .NET interface and Kernel property | Python FilterTypes | Runs | Security use |
|---|---|---|---|---|
| Function invocation | IFunctionInvocationFilter, FunctionInvocationFilters | FUNCTION_INVOCATION | Every KernelFunction call, prompt-based or method-based | Allowlist plugin and function names, validate arguments, check the caller's permission, log, override results |
| Prompt render | IPromptRenderFilter, PromptRenderFilters | PROMPT_RENDERING | Prompt rendering only (not method-based functions) | Redact PII before the prompt leaves, block a prompt by overriding the result, add guard text |
| Auto function invocation | IAutoFunctionInvocationFilter, AutoFunctionInvocationFilters | AUTO_FUNCTION_INVOCATION | Automatic function calling only | Approval gates, per-run call budgets, stop the loop with Terminate (.NET) or terminate (Python) |
- Put hard controls in the function invocation filter: it sees every call, including direct invocations and calls from prompt templates, not only those the model chose. An approval gate placed only in the auto function invocation filter does not cover the other paths.
- Fail closed: write filters so anything other than an explicit allow skips next and returns a safe result. Catch exceptions inside the filter and deny, rather than letting an error fall through to execution.
- Control order explicitly: Microsoft notes that filter order is not guaranteed when filters are added through dependency injection. Register security filters through the Kernel properties or add_filter and @kernel.filter, where filters run in the order added and the first wraps the second. Put authorisation outermost.
- Use permission checks before approval flows: the documentation gives the example of a filter validating that only a select group of people can start a process. Base the check on the authenticated user the host passes in, not on anything in the prompt.
- Do not over-trust redaction: a PII redaction prompt render filter reduces disclosure to the model provider but does not stop a plugin from returning sensitive data into the conversation. Filter results in the function invocation filter too.
This is the SK form of the controls described in the OWASP LLM Top 10 LLM06 Excessive Agency Guide.
Prompt templates and injection
SK's prompt injection documentation sets a zero trust default: content inserted into prompts, both input variables and function return values, is treated as unsafe and HTML encoded, then decoded automatically when the prompt is parsed into chat history. In practice this means inserted text is not parsed as prompt markup such as chat message tags.
| Setting | Scope of trust | Guidance |
|---|---|---|
| AllowUnsafeContent = true on an InputVariable | One named variable | The narrowest opt-out; use only for content your own code produced |
| AllowUnsafeContent = true on PromptTemplateConfig | Function call return values in that template | Avoid where any function returns external content (web, email, documents, MCP results) |
| AllowUnsafeContent = true on KernelPromptTemplateFactory or HandlebarsPromptTemplateFactory | All inserted content, reverting to the earlier behaviour | Treat as a finding in code review |
- Know the limit of encoding: encoding protects prompt structure. It does not stop a model from following instructions inside retrieved text. Indirect injection still needs the function and filter controls above. See the OWASP LLM Top 10 LLM01 Prompt Injection Guide.
- Check language coverage: as of November 2026 the prompt injection page describes the .NET behaviour and lists the Python and Java sections as coming soon. Python teams should confirm template encoding behaviour against their SDK version and add their own handling where needed.
- Search for opt-outs: add a repository search for AllowUnsafeContent to your pipeline and require a justification comment for each match.
Telemetry and data handling
SK emits OpenTelemetry data through experimental switches. The non-sensitive switch records model name, operation name and token usage; the sensitive switch adds prompts and completions.
| Setting | .NET (AppContext switch) | Python (environment variable) | Production |
|---|---|---|---|
| Diagnostics without content | Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnostics | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS | Recommended |
| Diagnostics with prompts and completions | Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnosticsSensitive | SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE | Off, or only in a controlled debug environment |
- Log levels matter too: Microsoft states that kernel function arguments and results are logged at trace level in .NET and debug level in Python. A verbose log level in production can write tool inputs and outputs, including personal data, to your log store.
- What to log instead: from the function invocation filter, write plugin name, function name, an argument hash or allowlisted fields, the decision (allowed, denied, approved) and the authenticated user. That gives an audit trail without content. See OpenTelemetry GenAI Semantic Conventions for Security Teams.
- Chat history retention: decide where chat history is stored and for how long. The Agent Framework migration guide notes that it has no session deletion API and that callers should track sessions and delete hosted history through the provider's SDK, so build deletion into the design before migrating.
Migrating to Microsoft Agent Framework securely
The Agent Framework migration guide shows agents created without a Kernel, tools registered directly on the agent, and threads replaced by sessions that the agent creates. Agent Framework has no plugin concept wrapping multiple functions, although you can still group them yourself.
| SK construct | Agent Framework equivalent | Security check during migration |
|---|---|---|
| Kernel with registered plugins | Tools passed to the agent | Re-derive each agent's tool list from need; do not copy every plugin across |
| Filters | Middleware and tool approval settings | Map each filter's decision to an equivalent control and test that denied calls are still denied |
| Host-supplied function context | Values bound through the tool's class instance | Confirm secrets and user context are still never model arguments |
| Agent threads | AgentSession | Plan deletion of hosted history through the provider |
| SK plugins kept for now | as_agent_framework_tool bridge (semantic-kernel 1.38 or later) | Patch both stacks; track SK components in the SBOM until removed |
- Inventory: list every SK application, its package versions, registered plugins, OpenAPI specs, MCP servers, credentials and filters. Search for AllowUnsafeContent and the sensitive telemetry switches.
- Harden in place: apply the function restrictions, filters and credential changes in this guide to SK first; they reduce risk now and become the specification for the migrated agent.
- Write tests for controls: for each denied function, unapproved write and missing permission, add a test that proves the call does not execute. Run the same tests against the Agent Framework version.
- Migrate one agent at a time: move agents first, bridging existing SK functions where needed, then rewrite plugins as native tools.
- Run side by side: compare tool call logs between old and new versions on the same inputs, watching for tools that are now auto-approved or advertised when they were not before.
- Roll back cleanly: keep the SK version deployable, with patched dependencies, until the new agent has passed its control tests in production for an agreed period.
Detection and measurement
- Denied calls: alert on spikes in filter denials for one user or session, which often indicate prompt injection attempts or a misconfigured tool list.
- Unexpected functions: alert when a function outside the expected set for an application is invoked.
- Credential use: watch the workload identity's sign-in and resource logs for access outside the plugins' normal targets.
Metrics that show the controls are working:
- Percentage of SK applications with an explicit advertised function list (target 100%).
- Number of AllowUnsafeContent opt-outs without a recorded justification (target zero).
- Percentage of write-capable functions behind an approval or permission filter.
- Number of production deployments with sensitive diagnostics enabled (target zero).
- Percentage of SK workloads with a dated Agent Framework migration plan.
- Days from an SK security release to deployment.
Framework mapping
| Control area | OWASP LLM Top 10 2025 | MITRE ATLAS | NIST SP 800-53 Rev. 5 / CSF 2.0 |
|---|---|---|---|
| Advertised function lists, approval filters | LLM06:2025 Excessive Agency | AML.T0053 AI Agent Tool Invocation | AC-6 Least Privilege; PR.AA-05 |
| Prompt template encoding, result filtering | LLM01:2025 Prompt Injection | AML.T0051 LLM Prompt Injection | SI-10 Information Input Validation |
| AuthCallback, host-supplied credentials | LLM02:2025 Sensitive Information Disclosure | AML.T0098 AI Agent Tool Credential Harvesting | IA-5 Authenticator Management |
| Filter audit logging, telemetry settings | LLM02:2025 Sensitive Information Disclosure | No specific technique | AU-12 Audit Record Generation; DE.CM-09 |
| Support window and migration | LLM03:2025 Supply Chain | No specific technique | SA-22 Unsupported System Components |
Common failure patterns
- All plugins advertised to every prompt. One Kernel registers search, email and admin plugins, and the default function choice offers all of them to every conversation.
- Approval only in the auto function invocation filter. Direct and template-driven invocations bypass it; the control belongs in the function invocation filter.
- Filter order left to dependency injection. A logging or caching filter ends up wrapping the authorisation filter and returns a cached result without the permission check.
- Factory-level AllowUnsafeContent. Set once to fix a rendering issue, it switches off encoding for every template in the application.
- Sensitive diagnostics left on after debugging. Prompts, completions and tool results land in a shared observability backend with broad read access.
- Remote OpenAPI spec loaded at start-up. A change to the hosted spec adds operations the model can call, with your AuthCallback attaching credentials to them.
Practitioner checklist
- Set an explicit advertised function list or included filters for every function calling request; never rely on the all-functions default.
- Implement a fail-closed function invocation filter with a plugin and function allowlist, argument validation and permission checks, registered through the Kernel so order is fixed.
- Gate write-capable functions with human approval or a permission filter, and set a per-run call budget with Terminate.
- Pass user identity, tenant and tokens as host-supplied context; never as model arguments or prompt text.
- Use Entra authentication or short-lived tokens for model services and OpenAPI plugins; keep any remaining keys in a secret store.
- Vendor OpenAPI specs into the repository and set ServerUrlOverride to the intended host.
- Search for AllowUnsafeContent and justify or remove every occurrence.
- Enable only non-sensitive OpenTelemetry diagnostics in production and keep log levels above trace and debug.
- Record SK versions in the SBOM, apply SK security releases promptly and set a dated Agent Framework migration plan.
- Write control tests that prove denied calls do not execute, and rerun them after migration.
Standards and references
- Microsoft Learn: Semantic Kernel filters
- Microsoft Learn: Protecting against prompt injection attacks in chat prompts
- Microsoft Learn: Function choice behaviors
- Microsoft Learn: Add plugins from OpenAPI specifications
- Microsoft Learn: Inspection of telemetry data with the console
- Microsoft Learn: Semantic Kernel to Agent Framework migration guide
- Microsoft Agent Framework blog: Semantic Kernel and Microsoft Agent Framework
- Microsoft: Semantic Kernel security policy
Related NHI Mgmt Group resources: Securing Agent Frameworks Guide · Microsoft Agent Framework and AutoGen security guide · AI Agent Tool and Plugin Security Guide · Agent Identity and Access Guide