Security
Authentication
The WorkManager gRPC and HTTP endpoints accept connections authenticated via Dapr's service-to-service mTLS. All inter-service calls between the API Gateway, WorkManager, and WebSocketManager are secured by Dapr's built-in mutual TLS.
For external client access, authentication should be handled at the API Gateway layer. See API Gateway Security for JWT bearer token and role-based authorization configuration.
Code Execution Safety
Python Workers
Python workers execute in a persistent sandboxed subprocess with the following protections:
- Launched with
-E -sflags (disablesPYTHON*environment variable injection and user site-packages) - Configurable blocked module list (blocks
subprocess,os,socket,requests, and other I/O modules by default) - Configurable package allow-list via
PYTHON_ALLOWED_PACKAGESenvironment variable - Code is injected directly via stdin — no temporary files written to disk
- Stderr output is captured as warning-level logs, not treated as errors
The subprocess communicates with the host via a JSON-line message loop over stdin/stdout and stays alive for the worker's lifetime (no per-message process spawn overhead).
C# Workers
C# workers run in-process within the WorkManager host. They share the host process's permissions. For maximum safety, use Python workers with the module blocklist or consider containerizing C# workers as sidecar containers in Kubernetes.
URL Validation
When loading worker code from a URL, the WorkManager validates:
- The URL host is in the
ALLOWED_CODE_SOURCE_HOSTSlist (if configured) - The URL does not resolve to a private/internal IP address (blocking SSRF attacks against
10.x,172.16.x,192.168.x,127.x,::1,fc00::/7,fe80::/10) - Optional SHA-256 content integrity verification via
ContentSha256field
Dapr Component Security
The WorkManager relies on Dapr for state storage and pub/sub messaging. Ensure Dapr components are configured with:
- State store: Authentication enabled (Redis password for Valkey)
- Pub/sub: Authentication enabled on the message broker
- mTLS: Enabled in Dapr configuration (default since Dapr 1.0)
Configuration & Secrets
The WorkManager reads its configuration from the standard .NET configuration sources (in order: appsettings.json, environment variables, command-line). The following keys control runtime behavior and are the only ones that carry security-sensitive values:
| Key | Default | Security role |
|---|---|---|
AllowedCodeSourceHosts |
(empty) | Host allow-list for worker code loaded from a URL. If empty, all hosts are allowed. Always set explicitly in production to prevent SSRF. |
ALLOWED_CODE_SOURCE_HOSTS |
(empty) | Environment-variable equivalent of the above (used by Program.cs:57). |
Logging:LogLevel:Default |
Information |
Set to Warning or higher in production to avoid leaking sensitive worker code or input data into logs. |
Worker Dapr component values (Redis password, broker credentials) are mounted at runtime via Dapr's secret management component (secretstores/kubernetes) — never commit them to source control. Dapr resolves them by key (e.g., stateStore.password) and the application reads them via DaprClient.GetSecretAsync.
Audit & Logging
The WorkManager emits structured logs for every state-mutating operation (CreateWorker, StartWorker, StopWorker, LoadCodeFromContent, LoadCodeFromUrl, DeleteWorker, RecoverWorkers) and every worker lifecycle event. Each log record includes the worker ID, the engine MIME type, and a correlation ID derived from the incoming gRPC request.
Fire-and-forget logging calls (sweeper events, completion continuations) are wrapped in try/catch and downgrade to LogLevel.Warning if the underlying stream write fails — this prevents observability failures from cascading into service failures.
Reporting Issues
Report security concerns to the Virtufin security team.