Case-variant workflow variables can bypass protected-value checks in .NET declarative workflows
Summary
Microsoft Agent Framework's .NET declarative workflow state can associate distinct, differently cased variable names with the same sensitivity metadata entry. A less-trusted workflow author can cause a variable containing a protected configuration value to lose its sensitivity label without changing its value. Subsequent HTTP requests or MCP tool invocations can then bypass the protected-value checks and disclose that value when the host enables those capabilities.
Details
WorkflowFormulaState stores variable values using case-sensitive keys, but affected versions store per-variable sensitivity labels using StringComparer.OrdinalIgnoreCase. Updating an ordinary variable whose name differs only by case can therefore overwrite the sensitivity label belonging to a different variable.
WorkflowFormulaState.Set, SetSensitivity, and GetSensitivity share this metadata store. Expression evaluation uses those labels, and HttpRequestExecutor.GetRequestValue and InvokeMcpToolExecutor.GetInvocationValue reject protected values based on the evaluated sensitivity. The mismatch can make these checks see an unprotected value while the original variable still contains the protected content.
Checkpoint restoration also writes sensitivity metadata through the same store. The fix's regression tests verify that case-variant variables retain independent labels after restoration...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| Microsoft.Agents.AI.Workflows.Declarative NuGet | < 1.26.0 | 1.26.0 |
Details and references
### Summary Microsoft Agent Framework's .NET declarative workflow state can associate distinct, differently cased variable names with the same sensitivity metadata entry. A less-trusted workflow author can cause a variable containing a protected configuration value to lose its sensitivity label without changing its value. Subsequent HTTP requests or MCP tool invocations can then bypass the protected-value checks and disclose that value when the host enables those capabilities. ### Details WorkflowFormulaState stores variable values using case-sensitive keys, but affected versions store per-variable sensitivity labels using StringComparer.OrdinalIgnoreCase. Updating an ordinary variable whose name differs only by case can therefore overwrite the sensitivity label belonging to a different variable. WorkflowFormulaState.Set, SetSensitivity, and GetSensitivity share this metadata store. Expression evaluation uses those labels, and HttpRequestExecutor.GetRequestValue and InvokeMcpToolExecutor.GetInvocationValue reject protected values based on the evaluated sensitivity. The mismatch can make these checks see an unprotected value while the original variable still contains the protected content. Checkpoint restoration also writes sensitivity metadata through the same store. The fix's regression tests verify that case-variant variables retain independent labels after restoration regardless of enumeration order. The demonstrated scenario requires the host to execute a workflow supplied by an untrusted or less-trusted author, expose a protected configuration value through the explicitly allowed Env scope, and enable HTTP requests or MCP tool invocations. Exposing configuration through Env is opt-in. ### Proof of concept Use only an isolated test harness, an artificial value such as TEST_ONLY_MARKER, and a recording mock handler that performs no network requests. 1. Configure the host to expose a test-only configuration entry through AllowedEnvironmentVariables. 2. In a declarative workflow, assign that Env value to a local variable. 3. Assign an ordinary literal to a distinct local variable whose name differs only by case. 4. Evaluate an HTTP request field or MCP tool argument that references the original variable, using the recording mock handler. 5. Compare with a control workflow that omits step 3. Expected: both workflows reject the protected value before invoking the handler. Affected behavior: the case-variant write clears the original variable's effective sensitivity label, allowing its unchanged marker value past the check. The original report demonstrated this behavior with loopback HTTP and MCP receivers on version 1.24.0; the mock-based outline above is a sanitized description, not a separately executed reproduction. ### Impact A workflow author can disclose protected configuration values made available to that workflow when the host also permits an applicable outbound action. The report demonstrated delivery through HTTP URLs, HTTP headers and JSON bodies, and MCP tool-call arguments. It also demonstrated relabeling through a case-variant Foreach index. The issue does not by itself expose configuration omitted from the Env allow-list, enable absent HTTP/MCP handlers, or demonstrate arbitrary code execution. Whether submitting a workflow requires authentication depends on the embedding application. No claim about exploitation in deployed applications is established here.