Memory Isolation
Each execution has exactly one ExecutionMemory instance. Memory from one execution is never shared with another execution — not even for the same workflow. Tenant isolation is enforced through the TenantId in ExecutionMetadata and by the execution orchestration layer, which never mixes memory instances across tenants.
Execution Isolation
| Isolation Boundary | Guarantee |
|---|---|
| Same workflow, different executions | Completely independent ExecutionMemory instances. Concurrent runs of the same workflow cannot read each other's nodeOutputs or globalVariables. |
| Different workflows, same tenant | Completely independent. ExecutionMemory is scoped to executionId, not processId. |
| Different tenants | Completely independent. TenantId is baked into ExecutionMetadata at creation and verified on every HIL resume path. |
Tenant Verification on Resume
When a suspended execution is resumed, the system verifies that the acting user's tenant matches the tenant recorded in the serialized ExecutionMetadata. A cross-tenant resume attempt is rejected before the memory is deserialized.
// WorkflowExecutionService.ResumeAsync — tenant verification
var suspended = await _repo.GetSuspendedExecutionAsync(executionId, ct);
// Check tenant before deserializing
if (suspended.TenantId != _tenantContext.TenantId)
{
_logger.LogWarning("Cross-tenant resume attempt blocked. ExecutionId={ExecutionId}", executionId);
throw new UnauthorizedException("Access denied");
}
// Safe to deserialize now
var memory = _serializer.Deserialize(suspended.ExecutionMemoryJson);
ExecutionMemory Does Not Enforce Tenant At Read Time
The in-memory ExecutionMemory object itself does not enforce tenant checks on GetNodeOutput calls — it is a plain in-memory dictionary. The tenant boundary is enforced at the layer that creates and dispatches the memory:
- The execution orchestration layer creates one memory per execution and passes it only to that execution's node runners.
- Executors cannot obtain another execution's memory object — they only receive their own via
ctx.ExecutionMemory. - HIL resume checks tenant before restoring memory.
PII and Sensitive Data Guidance
| Data Type | Guidance |
|---|---|
| PII (names, emails, IDs) | ExecutionMemory is ephemeral and in-process — acceptable to store for intra-execution use. However, if the execution involves a HIL node, it will be serialized to the database. Apply PII classification rules to the serialized form. |
| Authentication tokens or API keys | Never store in ExecutionMemory. Use ICredentialResolver at execution time — do not cache credentials in nodeOutputs. |
| Financial amounts | Acceptable — they are structured data. Ensure they are passed by value, not by reference to a mutable object. |
Node Inspector Exposure
The Node Inspector tab in the Observer Panel displays the inputData and outputData for nodes in a completed or running execution. These values come from a snapshot of ExecutionMemory.nodeOutputs captured by the engine after each node runs. Users with execution:view permission on the process can see this data — design your output accordingly if it contains sensitive values.