elsa-core/doc/wiki/expressions-and-scripting.md
Sipke Schoorstra 2fa1a9ef8e
[codex] Harden C# expression host-code execution (#7519)
* Harden C# expression host-code execution

* Address script authorization review feedback

* Harden script authorization failure responses

* Address code quality review feedback

* Use explicit failure filter in script authorization

* Centralize script activity type names

* Address script authorization review feedback
2026-05-21 00:50:25 +02:00

6.3 KiB

Expressions And Scripting

Expressions let workflow inputs be dynamic. The base expression feature provides evaluator infrastructure; language modules add concrete evaluators, descriptors, activities, and type/function definitions.

Base Expressions

ExpressionsFeature registers:

  • IExpressionEvaluator
  • IWellKnownTypeRegistry

The base project is Elsa.Expressions. It is intentionally small and does not own language-specific runtime behavior.

Language Modules

Module Feature Evaluator Notes
Elsa.Expressions.JavaScript JavaScriptFeature Jint-backed IJavaScriptEvaluator Adds type definitions, function definitions, RunJavaScript, and FastEndpoints assembly.
Elsa.Expressions.CSharp CSharpFeature Roslyn scripting-backed ICSharpEvaluator Adds RunCSharp, descriptors, and C# options.
Elsa.Expressions.Python PythonFeature pythonnet-backed IPythonEvaluator Registers PythonGlobalInterpreterManager as a hosted service.
Elsa.Expressions.Liquid LiquidFeature Fluid-backed Liquid manager Adds Liquid filters and parser services.

JavaScript

JavaScript is the richest expression module. It registers:

  • IJavaScriptEvaluator
  • ITypeDefinitionService
  • type describers and type definition renderers
  • function definition providers
  • variable definition providers
  • RunJavaScript activity
  • TypeScript definition support
  • expression descriptors for Studio

Configuration example from Elsa.Server.Web/Program.cs:

elsa.UseJavaScript(options =>
{
    options.AllowClrAccess = true;
    options.ConfigureEngine(engine =>
    {
        engine.Execute("function greet(name) { return `Hello ${name}!`; }");
    });
});

Additional JavaScript libraries are in Elsa.Expressions.JavaScript.Libraries, including Lodash, Lodash FP, and Moment feature packages.

CSharp

CSharpFeature registers C# descriptors and ICSharpEvaluator, then adds activities from its assembly. The reference server demonstrates configuring wrappers and appending helper scripts:

elsa.UseCSharp(options =>
{
    options.AllowHostCodeExecution = true;
    options.DisableWrappers = disableVariableWrappers;
    options.AppendScript("string Greet(string name) => $\"Hello {name}!\";");
});

Roslyn C# scripting is privileged host-code execution, not a sandbox. Hosts must explicitly set CSharpOptions.AllowHostCodeExecution to true before C# expressions or RunCSharp can be authored or executed. API callers that author, publish, dispatch, or directly execute workflows containing C# must have the exec:csharp-expressions permission.

Python

PythonFeature registers pythonnet-based evaluation and configures PythonGlobalInterpreterManager as a hosted service. Python.NET execution is privileged host-code execution, not a sandbox. Python code can access host process capabilities through pythonnet and must only be enabled for trusted workflow authors.

Hosts must explicitly set PythonOptions.AllowHostCodeExecution to true before Python expressions or RunPython can be authored or executed. API callers that author, publish, dispatch, or directly execute workflows containing Python must have the exec:python-expressions permission. Hosts must also configure the Python DLL path or set PYTHONNET_PYDLL.

The reference server binds Scripting:Python configuration in Program.cs.

Python.NET hardening is part of the broader script execution security tracking in #7096.

Liquid

LiquidFeature registers Fluid options, parser services, expression descriptors, and built-in filters:

  • array filters
  • string filters
  • number filters
  • miscellaneous filters
  • base64
  • keys

The reference server configures the Fluid encoder to HtmlEncoder.Default.

Expression Descriptors

Expression descriptors let Studio know which expression languages are available and how to present them. Providers are registered by language features, for example:

  • JavaScriptExpressionDescriptorProvider
  • CSharpExpressionDescriptorProvider
  • PythonExpressionDescriptorProvider
  • LiquidExpressionDescriptorProvider

The API exposes descriptors under /elsa/api/descriptors/expression-descriptors.

Type Aliases

Expression modules and activity modules register type aliases through ExpressionOptions. HTTP, for example, adds aliases such as HttpRequest, HttpResponse, RouteData, FormFile, and Downloadable in HttpFeature.

ElsaScript Relationship

ElsaScript does not replace expression languages. It uses Elsa's expression providers through language prefixes such as js =>, cs =>, py =>, and liquid =>. See ElsaScript README.

Testing

Expression tests are split by concern:

Prefer unit tests for parser/evaluator behavior and integration tests when expression evaluation interacts with workflow variables, activity outputs, or designer descriptors.