Visitar URL original
Releases · dapr/dapr · GitHub
Skip to content

Releases: dapr/dapr

Dapr Runtime v1.19.1

Choose a tag to compare

@dapr-bot dapr-bot released this 31 Oct 13:03
cfb5ee0

Dapr 1.19.1

This update contains the following bug fixes and improvements:

Sidecar leaked connections while the Placement service was unreachable

Problem

While the sidecar could not reach the Placement service, it tried to connect about twice a second. Each attempt opened a new gRPC connection, and the sidecar did not close it when the attempt failed. Each leaked connection kept trying to reach Placement, with its own goroutines, until the sidecar restarted.
The sidecar also did not close the connection when a stream to Placement ended.

Impact

You were affected if a sidecar could not reach the Placement service for a sustained period, for example while its pods restarted or crash looped. The goroutine count and memory use of every sidecar that connects to Placement grew for as long as the outage lasted. In a test with Placement stopped, the goroutine count of the sidecar grew by about 8 every second. Restarting the sidecar released the connections.

Root Cause

The sidecar dials a connection to a Placement host and then opens the Placement stream on it. The dial does not wait for the host, so it succeeds while Placement is down, and only opening the stream fails.
When opening the stream failed, the sidecar returned the error without closing the connection, and the retry loop dialed another one. When a stream ended, the sidecar cancelled the stream but did not close its connection.

Solution

The sidecar closes the connection when opening the stream fails, and closes it when the stream ends.

SQLite state store writes failed with database is locked after a cancelled read

Problem

After a read from the SQLite state store was cancelled, a later write on the same connection could fail at once with database is locked (SQLITE_BUSY).
The write did not wait for the configured busyTimeout. The error continued while that connection stayed in the connection pool.

Impact

You were affected if you use the SQLite state store, also as the actor or workflow state store, and requests to it are cancelled.
For example, a client timeout, a workflow worker that disconnects, or a sidecar shutdown cancels requests.
Workflow starts, raised events and state writes could fail with this error.

Root Cause

The SQLite driver, modernc.org/sqlite v1.34.5, did not close the rows of a query when the query context was cancelled after the first row was returned.
The connection kept its read transaction open and went back to the pool.
SQLite does not wait for the busy timeout when the connection already holds a read transaction.
So the next write transaction on that connection failed at once.

Solution

Dapr now uses modernc.org/sqlite v1.42.2.
This version closes the rows of a cancelled query.
It also fixes a cancelled context that interrupted a later, unrelated query on the same connection.

Security: Service invocation access control bypass with other percent-encoded characters and path parameters

Problem

Service invocation access control policies match the invoked method literally, after lowercasing it for HTTP apps.
The method is sent to an HTTP app unchanged, and the app's HTTP server decodes percent-encoded characters before routing.
A method that percent-encoded any other character, such as %61dmin/secret, therefore did not match a rule for /admin/secret, but the app decoded it to /admin/secret.
Some HTTP servers, such as Java servlet containers, also drop ; path parameters before routing, so admin;x/secret reached /admin/secret on those apps.

This completes the fix for "Security: Service invocation access control bypass with percent-encoded path characters" in Dapr 1.17.16 and 1.18.6, which only covered %2F, %5C and %2E.

Impact

You were affected if you used service invocation access control policies with a deny-list (defaultAction: allow and operations set to action: deny), and the target application uses the HTTP app protocol.
An attacker needs an application identity that the policy allows to call the target.
They could invoke a denied operation such as /admin/secret by sending the method %61dmin/secret through the gRPC API, or %2561dmin/secret through the HTTP API.
On apps that drop ; path parameters, admin;x/secret worked as well.
Allow-list policies (defaultAction: deny) were not affected, because an encoded method matched no allow rule.

Reported by Lee SeongHyeon.

Root Cause

The access control check compared the method as a literal string, while the HTTP app routes on the decoded path without ; parameters.
The earlier fix rejected only the encoded characters that change how the path splits into segments, and passed all other percent-encoded sequences through.

Solution

For HTTP apps, the access control check now matches policies against the method as the app routes it: percent-encoded characters decoded once, then lowercased.
Some HTTP servers drop ; path parameters before routing and others do not, so the method must be allowed both with and without its ; parameters.
A request is denied if its method has an invalid percent-escape, or if removing ; parameters leaves an empty, . or .. path segment, as with ..;x.
An encoded * (%2A) is not decoded, so it never acts as a wildcard.
Operations in access control policies are read the same way, so existing rules keep matching.
If several operations in a policy resolve to the same path, their rules are combined, and deny wins where they conflict.
The method sent to the app is not changed, so applications that use encoded characters in method names keep working.
gRPC apps are unchanged.

Allow rules now also match encoded spellings of the allowed path, for example /%70ublic for a /public rule.
A policy operation that contains ; now ends at the ;.

Security: Scheduler delivered another app's workflow reminders to any app in the namespace

Problem

When a sidecar connects to the Scheduler to receive job and reminder triggers (WatchJobs), it declares the actor types it hosts and per actor type concurrency limits.
The Scheduler checked that the caller's identity matched the app ID and namespace in the request, but not that the caller owned the declared actor types.
An app could declare another app's reserved internal actor types, such as dapr.internal.<namespace>.<app ID>.workflow and dapr.internal.<namespace>.<app ID>.activity.
The Scheduler then delivered a share of that app's workflow and activity reminder triggers to it, and applied its concurrency limits to the other app's actor types.

Impact

Any workload with a Dapr identity for an app in a namespace could call the Scheduler directly and receive workflow and activity reminder triggers of other apps in the same namespace.
The triggers include the reminder data, such as workflow inputs and history events.
By acknowledging the triggers without acting on them, or by setting a low concurrency limit, it could also stall those workflows.
Other namespaces were not affected.

Root Cause

Job and reminder management and actor placement already reject internal actor types that do not belong to the calling app.
The WatchJobs stream setup did not apply the same check to the actor types and concurrency limits it registers.

Solution

The Scheduler now rejects a WatchJobs stream with PermissionDenied if it declares, or sets a concurrency limit on, an internal actor type (dapr.internal.*) that does not belong to the calling app and namespace.
Sidecars only declare their own internal actor types, so they are not affected. User-defined actor types are unchanged.

Security: AP...

Read more

Dapr Runtime v1.18.10

Choose a tag to compare

@dapr-bot dapr-bot released this 31 Oct 13:04
9afd6ad

Dapr 1.18.10

This update contains the following bug fixes and improvements:

Sidecar leaked connections while the Placement service was unreachable

Problem

While the sidecar could not reach the Placement service, it tried to connect about twice a second. Each attempt opened a new gRPC connection, and the sidecar did not close it when the attempt failed. Each leaked connection kept trying to reach Placement, with its own goroutines, until the sidecar restarted.
The sidecar also did not close the connection when a stream to Placement ended.

Impact

You were affected if a sidecar could not reach the Placement service for a sustained period, for example while its pods restarted or crash looped. The goroutine count and memory use of every sidecar that connects to Placement grew for as long as the outage lasted. Restarting the sidecar released the connections.

Root Cause

The sidecar dials a connection to a Placement host and then opens the Placement stream on it. The dial does not wait for the host, so it succeeds while Placement is down, and only opening the stream fails.
When opening the stream failed, the sidecar returned the error without closing the connection, and the retry loop dialed another one. When a stream ended, the sidecar cancelled the stream but did not close its connection.

Solution

The sidecar closes the connection when opening the stream fails, and closes it when the stream ends.

Security: Service invocation access control bypass with other percent-encoded characters and path parameters

Problem

Service invocation access control policies match the invoked method literally, after lowercasing it for HTTP apps.
The method is sent to an HTTP app unchanged, and the app's HTTP server decodes percent-encoded characters before routing.
A method that percent-encoded any other character, such as %61dmin/secret, therefore did not match a rule for /admin/secret, but the app decoded it to /admin/secret.
Some HTTP servers, such as Java servlet containers, also drop ; path parameters before routing, so admin;x/secret reached /admin/secret on those apps.

This completes the fix for "Security: Service invocation access control bypass with percent-encoded path characters" in Dapr 1.17.16 and 1.18.6, which only covered %2F, %5C and %2E.

Impact

You were affected if you used service invocation access control policies with a deny-list (defaultAction: allow and operations set to action: deny), and the target application uses the HTTP app protocol.
An attacker needs an application identity that the policy allows to call the target.
They could invoke a denied operation such as /admin/secret by sending the method %61dmin/secret through the gRPC API, or %2561dmin/secret through the HTTP API.
On apps that drop ; path parameters, admin;x/secret worked as well.
Allow-list policies (defaultAction: deny) were not affected, because an encoded method matched no allow rule.

Reported by Lee SeongHyeon.

Root Cause

The access control check compared the method as a literal string, while the HTTP app routes on the decoded path without ; parameters.
The earlier fix rejected only the encoded characters that change how the path splits into segments, and passed all other percent-encoded sequences through.

Solution

For HTTP apps, the access control check now matches policies against the method as the app routes it: percent-encoded characters decoded once, then lowercased.
Some HTTP servers drop ; path parameters before routing and others do not, so the method must be allowed both with and without its ; parameters.
A request is denied if its method has an invalid percent-escape, or if removing ; parameters leaves an empty, . or .. path segment, as with ..;x.
An encoded * (%2A) is not decoded, so it never acts as a wildcard.
Operations in access control policies are read the same way, so existing rules keep matching.
If several operations in a policy resolve to the same path, their rules are combined, and deny wins where they conflict.
The method sent to the app is not changed, so applications that use encoded characters in method names keep working.
gRPC apps are unchanged.

Allow rules now also match encoded spellings of the allowed path, for example /%70ublic for a /public rule.
A policy operation that contains ; now ends at the ;.

Workflows became permanently unrecoverable after a save with a timer in the inbox

Problem

A workflow could get stuck in a state that Dapr could no longer load.
Status queries failed, the workflow never resumed, and both purge and force purge failed.
Loading the workflow failed with an error like inbox key 'inbox-000000' declared in metadata (inboxLength=1) but missing from state store.

Impact

You were affected if Dapr saved a workflow's state while a fired timer event was still waiting to be processed.
This happened when a workflow stalled on a timer wake-up because of a version mismatch or an oversized payload.
It also happened when Dapr abandoned a continue-as-new.
The only way to recover the instance was to edit its state in the state store by hand.
The same bug could also store the timer event under the wrong key and drop another event that arrived while the timer event was waiting.

Root Cause

When a timer fires, Dapr adds a TimerFired event to the workflow inbox in memory, but never saves it as an inbox key in the state store.
The scheduler job holds the event instead, and the scheduler deletes the job only after Dapr saves the run that consumed it.
When Dapr saved the workflow state, it still counted the timer event in the inbox length stored in the workflow metadata.
Since Dapr 1.18.0, loading a workflow fails if the metadata declares an inbox key that does not exist in the state store.

Solution

Dapr no longer counts timer events in the stored inbox length, and no longer includes them when it computes the inbox keys to save.

Security: Scheduler delivered another app's workflow reminders to any app in the namespace

Problem

When a sidecar connects to the Scheduler to receive job and reminder triggers (WatchJobs), it declares the actor types it hosts and per actor type concurrency limits.
The Scheduler checked that the caller's identity matched the app ID and namespace in the request, but not that the caller owned the declared actor types.
An app could declare another app's reserved internal actor types, such as dapr.internal.<namespace>.<app ID>.workflow and dapr.internal.<namespace>.<app ID>.activity.
The Scheduler then delivered a share of that app's workflow and activity reminder triggers to it, and applied its concurrency limits to the other app's actor types.

Impact

Any workload with a Dapr identity for an app in a namespace could call the Scheduler directly and receive workflow and activity reminder triggers of other apps in the same namespace.
The triggers include the reminder data, such as workflow inputs and history events.
By acknowledging the triggers without acting on them, or by setting a low concurrency limit, it could also stall those workflows.
Other namespaces were not affected.

Root Cause

Job and reminder management and actor placement already reject internal actor types that do not belong to the calling app.
The WatchJobs stream setup did not apply the same check to the actor types and concurrency limits it registers.

Solution

The Scheduler now rejects a WatchJobs stream with PermissionDenied if it declares, or sets a concurrency limit on, an internal actor type (dapr.internal.*) that does not belong to t...

Read more

Dapr Runtime v1.17.19

Choose a tag to compare

@dapr-bot dapr-bot released this 31 Oct 13:03
0bd0aa3

Dapr 1.17.19

This update contains the following security fixes:

Security: Service invocation access control bypass with other percent-encoded characters and path parameters

Problem

Service invocation access control policies match the invoked method literally, after lowercasing it for HTTP apps.
The method is sent to an HTTP app unchanged, and the app's HTTP server decodes percent-encoded characters before routing.
A method that percent-encoded any other character, such as %61dmin/secret, therefore did not match a rule for /admin/secret, but the app decoded it to /admin/secret.
Some HTTP servers, such as Java servlet containers, also drop ; path parameters before routing, so admin;x/secret reached /admin/secret on those apps.

This completes the fix for "Security: Service invocation access control bypass with percent-encoded path characters" in Dapr 1.17.16 and 1.18.6, which only covered %2F, %5C and %2E.

Impact

You were affected if you used service invocation access control policies with a deny-list (defaultAction: allow and operations set to action: deny), and the target application uses the HTTP app protocol.
An attacker needs an application identity that the policy allows to call the target.
They could invoke a denied operation such as /admin/secret by sending the method %61dmin/secret through the gRPC API, or %2561dmin/secret through the HTTP API.
On apps that drop ; path parameters, admin;x/secret worked as well.
Allow-list policies (defaultAction: deny) were not affected, because an encoded method matched no allow rule.

Reported by Lee SeongHyeon.

Root Cause

The access control check compared the method as a literal string, while the HTTP app routes on the decoded path without ; parameters.
The earlier fix rejected only the encoded characters that change how the path splits into segments, and passed all other percent-encoded sequences through.

Solution

For HTTP apps, the access control check now matches policies against the method as the app routes it: percent-encoded characters decoded once, then lowercased.
Some HTTP servers drop ; path parameters before routing and others do not, so the method must be allowed both with and without its ; parameters.
A request is denied if its method has an invalid percent-escape, or if removing ; parameters leaves an empty, . or .. path segment, as with ..;x.
An encoded * (%2A) is not decoded, so it never acts as a wildcard.
Operations in access control policies are read the same way, so existing rules keep matching.
If several operations in a policy resolve to the same path, their rules are combined, and deny wins where they conflict.
The method sent to the app is not changed, so applications that use encoded characters in method names keep working.
gRPC apps are unchanged.

Allow rules now also match encoded spellings of the allowed path, for example /%70ublic for a /public rule.
A policy operation that contains ; now ends at the ;.

Security: Scheduler delivered another app's workflow reminders to any app in the namespace

Problem

When a sidecar connects to the Scheduler to receive job and reminder triggers (WatchJobs), it declares the actor types it hosts.
The Scheduler checked that the caller's identity matched the app ID and namespace in the request, but not that the caller owned the declared actor types.
An app could declare another app's reserved internal actor types, such as dapr.internal.<namespace>.<app ID>.workflow and dapr.internal.<namespace>.<app ID>.activity.
The Scheduler then delivered a share of that app's workflow and activity reminder triggers to it.

Impact

Any workload with a Dapr identity for an app in a namespace could call the Scheduler directly and receive workflow and activity reminder triggers of other apps in the same namespace.
The triggers include the reminder data, such as workflow inputs and history events.
By acknowledging the triggers without acting on them, it could also stall those workflows.
Other namespaces were not affected.

Root Cause

Job and reminder management and actor placement already reject internal actor types that do not belong to the calling app.
The WatchJobs stream setup did not apply the same check to the actor types it registers.

Solution

The Scheduler now rejects a WatchJobs stream with PermissionDenied if it declares an internal actor type (dapr.internal.*) that does not belong to the calling app and namespace.
Sidecars only declare their own internal actor types, so they are not affected. User-defined actor types are unchanged.

Security: API token check bypassed with a percent-encoded health check path

Problem

When an API token is configured (DAPR_API_TOKEN), every request to the Dapr HTTP API must carry it in the dapr-api-token header, except GET /v1.0/healthz and GET /v1.0/healthz/outbound.
The exemption compared the decoded request path with these routes, while the router matches the escaped path.
A request such as GET /v1.0/healt%68z or GET /v1.0%2Fhealthz decoded to /v1.0/healthz and skipped the token check, but matched no route.
Unmatched requests are handled by service invocation, so the request was invoked without a token.

Impact

You were affected if you configured an API token and untrusted clients can reach the Dapr HTTP API port.
In Kubernetes the injector binds the API to the loopback interface by default, so only processes in the same pod could reach it unless dapr.io/sidecar-listen-addresses was changed.
In self-hosted mode the API listens on all interfaces by default.

A client without the token could make the sidecar send a GET request to the target named in the dapr-app-id header: the local app, any app in the mesh, an HTTPEndpoint resource, or any http:// or https:// URL the sidecar can reach (server-side request forgery).
The method was always v1.0/healthz, but the query string, headers and body were passed through.
Calls to other apps were sent with the sidecar's own identity, so their access control policies treated them as calls from this app.

This is the same class of issue as the earlier API token authentication bypass.

Reported by Lee SeongHyeon.

Root Cause

The API token middleware checked whether a request was a health check by comparing the decoded URL.Path.
The router matches routes against the escaped path, so any request that percent-encoded a character of the health check path was exempt from the token but was not routed to the health check handler.

Solution

The API token middleware now compares the same escaped path the router matches, so a percent-encoded health check path requires the API token.
GET /v1.0/healthz and GET /v1.0/healthz/outbound remain exempt.

Security: Sidecars relayed proxied gRPC calls from other sidecars under their own identity

Problem

Each sidecar listens on an internal gRPC port (50002 by default) that other sidecars use for service invocation, including gRPC proxying.
When a gRPC proxy call arrived on that port addressed to a different app (in the dapr-callee-app-id or dapr-app-id metadata), the sidecar forwarded it to that app's sidecar.
It set itself as the caller (dapr-caller-app-id and dapr-caller-namespace) and connected with its own mTLS identity.
The sidecar also treated an app with its own app ID in another namespace as the local app.

Impact

Any workload with a Dapr identity, in any namespace, could relay a gRPC call through another app's sidecar.
For example, a workload could send a call to app B's internal port addressed to app C.
App C's sidecar then evaluated its access control policy against app B, not the real caller, and app C received dapr-caller-app-id: B.
This bypassed service invocation access control policies, and any caller checks in application code, whenever so...

Read more

Dapr Runtime v1.19.0

Choose a tag to compare

@dapr-bot dapr-bot released this 22 Oct 13:54
cd59bfb

Dapr 1.19

We're excited to announce the release of Dapr 1.19!

The main changes in this release:

  • Faster workflows, jobs and reminders. In the nightly performance tests against 1.18.0, workflow throughput is up to 40% higher. The p99 latency of actor reminder registration is 71% lower, and the p99 latency of Jobs scheduling is 33% lower. Workflow workers in the Python, Java, .NET and Go SDKs now get only the new events of each turn, not the full history.
  • Workflows across apps. A workflow client can now start, get, raise events on, pause, resume, terminate, purge and rerun a workflow that another app owns. Access policies decide which app can do what. A new requires rule allows a schedule only when the caller's history contains the required upstream events. A workflow can also start a detached workflow that outlives it.
  • New building blocks (alpha). Binary Store stores large files in Amazon S3 and S3-compatible stores, Azure Blob Storage, Azure Data Lake Storage, Google Cloud Storage and OCI Object Storage. Search and Vector index and query documents and vectors, with Meilisearch components.
  • Dapr MCP server (alpha). The Dapr MCP server gives AI agents and IDE assistants the building blocks of a sidecar as Model Context Protocol tools. It ships as a separate binary, on its own release cycle.
  • Actors. With actor placement in the Scheduler (opt-in), each reminder goes straight to the host that runs the actor. The cluster then does not need the Placement service. New APIs list and get actor timers over HTTP and gRPC, and list reminders over HTTP. When an actor moves to another host, the old host deletes its timers, so they no longer fire twice.
  • Kafka transactions. Kafka pub/sub can make a bulk publish atomic, read only committed records, and run consume-transform-produce in one transaction. All three are opt-in.
  • Operations. Logs can go to several destinations, with file rotation and a configurable timestamp format. Workload identity certificates carry the image references of the pod. Every Kubernetes Service that Dapr creates sets appProtocol for service meshes.
  • Security. Five security fixes. Four of them, for service invocation, the Scheduler and workflows, also shipped in 1.18.6. The fifth makes the Operator enforce app scopes and configuration assignment, and it also shipped in 1.18.9 and 1.17.18. Four of the five change behavior.

Read Breaking Changes and Deprecation Notices before you upgrade. 1.19 contains behavior changes that can affect an upgrade, mostly in the SDKs.

Thanks to all the new and existing contributors who helped make this release happen.

If you're new to Dapr, visit the getting started page and familiarize yourself with Dapr.

The docs have been updated with all the new features and changes of this release. To get started with new capabilities introduced in this release, go to the Concepts and the Developing applications.

Go to the upgrading Dapr section for steps to upgrade to version 1.19.

Acknowledgements

Thanks to everyone who made this release possible!

@acroca, @adam6878, @Advait2912, @anneheartrecord, @anxkhn, @arturotrenard, @baltasarblanco, @CasperGN, @cicoyle, @DamienCassou, @famarting, @gargsajal9, @GHX5T-SOL, @icmp0x8, @ihopenre-eng, @javier-aliaga, @jjcollinge, @jongep86, @JoshVanL, @jslatten, @kayvonkhosrowpour, @kshitizj03, @LiBaoxuan-Neil, @LilDojd, @LindseyZ1205, @lrascao, @m3nax, @magic-peach, @manduinca, @marcduiker, @matheusandre1, @mikeee, @MrMint, @MsfPablo, @mtaghavi2005, @Mukuwul, @MyMirelHub, @nelson-parente, @olitomlinson, @pablochacin, @passuied, @Psingle20, @pujitha24, @RakeshCodeLab, @Rishabh-git10, @SaiPisey2, @SarthakB11, @seherv, @sicoyle, @siri-varma, @somaz94, @stywzn, @tezizzm, @vip892766gma, @WhitWaldo, @yaron2, @Yash121l

Highlights

These are the v1.19 release highlights:

Faster workflows, jobs and reminders

Compared with the published v1.18.0 run, the nightly performance tests on master show:

  • Workflows: throughput is 40% higher in TestWorkflowWithConstantVUs and 32% higher in TestSeriesWorkflowWithMaxVUs.
  • Jobs scheduling: p99 latency is 33% lower (39.5 ms to 26.3 ms), and the test now sustains the full requested 1000 QPS (921 QPS on 1.18.0).
  • Actor reminder registration: p99 latency is 71% lower (148 ms to 43 ms), at 43% more registrations per second.
  • Configuration subscribe: throughput is 67% higher over HTTP and about 2.8x over gRPC. This test varies up to 3x between runs, so treat the gRPC figure as indicative.

Service invocation, state and pub/sub publish show no change beyond run-to-run noise. The figures are medians of 8 runs from 23/09/2026 to 02/10/2026, on the same cluster as the v1.18.0 run.

Changes in this area include:

  • Event-driven completion of work items.
  • Cached tag maps for metrics on hot paths.
  • Fewer state copies and event marshals per workflow turn.
  • A separate size and payload-ratio aggregation for each meter.
  • Large fan-outs: an empty-inbox wake-up reloads the workflow state only when its cache is stale. Before, each such wake-up re-read the whole history.

For workflows that run for minutes or hours, the workflow block of the metrics settings in Configuration now takes its own latencyDistributionBuckets, with a latencyDistributionUnits such as 1s. The workflow and activity execution latency histograms then use buckets that fit those durations, instead of the shared millisecond buckets, where every long workflow landed in the top bucket. The repository also ships Grafana dashboards for workflows and for the Scheduler in grafana/: execution and activity rates, latency percentiles, failures, client operations and payload size against the limit, which no dashboard charted before. The etcd panels of the Scheduler dashboard need --etcd-metrics=extensive.

The 1.19 charts are published after the GA tag on the performance results page.

Workflow workers get only the new history

Long-running workflows now spend less time on each turn. Before 1.19, a workflow worker received the full history of an instance on every turn. For long-running instances, sending and parsing that history took most of the time of each turn.

A worker can now advertise the WORKER_CAPABILITY_STATEFUL_HISTORY capability on its work-item stream. The worker then keeps the history of each instance in a cache. When the worker already has the history from an earlier turn on the same stream, the sidecar sends only the new events. The worker builds the full history from its cache and the new events, so the sidecar no longer re-sends, and the worker no longer re-parses, the whole history on every turn. On a reconnect the sidecar sends the full history. If the worker has evicted the instance from its cache, it fetches the full history from the sidecar. Either case adds latency, but it does not change the result.

The protocol is in durabletask-go#110. The SDKs that support it turn it on by default:

SDK Stateful history
Python On by default. To turn it off, set disable_stateful_history=True on WorkflowRuntime.
Java On by default. To turn it off, call WorkflowRuntimeBuilder.withStatefulHistoryDisabled(true).
.NET On by default. To turn it off, set WorkflowRuntimeOptions.DisableStatefulHistory.
Go On by default from go-sdk v1.16.0 (durabletask-go v0.15.0). The Go SDK has no switch to turn it off; client.WithStatefulHistoryDisabled() in durabletask-go does.
JavaScript No. The new JavaScript workflow engine does not use the shared DurableTask client library.

Health pings on idle work-item streams

On an idle work-item stream, the sidecar now sends a health ping every 30 seconds to a worker that advertises the WORKER_CAPABILITY_HEALTH_PING capability. Load balancers such as AWS ALB and nginx close an idle stream after 60 seconds, and before 1.19 that cost the worker a reconnect and a full history resend. The 1.19 Python, Java and .NET SDKs and durabletask-go v0.15 (Go SDK 1.16) advertise the capability. Set DAPR_WORKFLOW_HEALTH_PING_INTERVAL on daprd to change the interval.

WorkflowsFastPath preview feature

The new WorkflowsFastPath preview feature is off by default. With it, a workflow wake-up runs on th...

Read more

Dapr Runtime v1.19.0-rc.7

Pre-release

Choose a tag to compare

@dapr-bot dapr-bot released this 22 Oct 00:06
d0d21cf

This is the release candidate 1.19.0-rc.7

What's Changed

  • [Backport release-1.19] Operator: enforce app scopes and configuration assignment by @dapr-bot in #10893
  • [Backport release-1.19] workflow: ack a settled completed workflow's wake-ups without a full reload by @dapr-bot in #10896

Full Changelog: v1.19.0-rc.6...v1.19.0-rc.7

Dapr Runtime v1.19.0-rc.6

Pre-release

Choose a tag to compare

@dapr-bot dapr-bot released this 21 Oct 13:36
b447153

This is the release candidate 1.19.0-rc.6

What's Changed

  • [Backport release-1.19] grpc: return DeadlineExceeded for a timed-out actor invocation by @dapr-bot in #10886
  • [Backport release-1.19] tests, ci: fix integration flakes, the 1.18 skew run and push retries by @dapr-bot in #10885
  • [Backport release-1.19] Updates components-contrib to HEAD by @dapr-bot in #10888

Full Changelog: v1.19.0-rc.5...v1.19.0-rc.6

Dapr Runtime v1.19.0-rc.5

Pre-release

Choose a tag to compare

@dapr-bot dapr-bot released this 21 Oct 09:11
4790006

This is the release candidate 1.19.0-rc.5

What's Changed

  • [Backport release-1.19] chore: pin dapr/kit v0.19.0 and durabletask-go v0.15.1 by @dapr-bot in #10846
  • [Backport release-1.19] fix: memory/routine leak - grpc connections unclosed by @dapr-bot in #10847
  • [Backport release-1.19] Fix actor lock dispatching queued calls when a queued call is cancelled by @dapr-bot in #10849
  • [Backport release-1.19] fix: start a root span for pubsub deliveries with no inbound trace context by @dapr-bot in #10844
  • [Backport release-1.19] ci: verify golangci-lint config only on pull requests by @dapr-bot in #10854
  • [Backport release-1.19] fix: treat a gRPC Canceled under a policy timeout as the timeout by @dapr-bot in #10858
  • [Backport release-1.19] integration: assert at-least-once in fastpath activity tests; unflake 3 by @dapr-bot in #10856
  • [Backport release-1.19] fix: keep the replay buffer when a request body reader is not read by @dapr-bot in #10857
  • [Backport release-1.19] Fix tracing spans not exported after a SIGHUP restart by @dapr-bot in #10860
  • [Backport release-1.19] ci: remove sync-release-branch workflow by @dapr-bot in #10855
  • [Backport release-1.19] Release notes for redis Entra ID fix by @dapr-bot in #10864
  • [Backport release-1.19] Clear error when no workflow worker is connected by @dapr-bot in #10867
  • [Backport release-1.19] feat: search and vector blocks by @dapr-bot in #10866
  • [Backport release-1.19] update docs to match behavior by @dapr-bot in #10872
  • [Backport release-1.19] Scope scheduler pod RBAC to its own namespace by @dapr-bot in #10875
  • [Backport release-1.19] Sidecar leaked a connection every second while the Scheduler was unreachable by @dapr-bot in #10884
  • [Backport release-1.19] Go: update 1.26.9 -> 1.26.10 by @dapr-bot in #10882

Full Changelog: v1.19.0-rc.4...v1.19.0-rc.5

Dapr Runtime v1.18.9

Choose a tag to compare

@dapr-bot dapr-bot released this 21 Oct 23:25
7b4c383

Dapr 1.18.9

This update contains the following security fix:

Security: Operator disclosed resources and secrets scoped to other apps

Problem

In Kubernetes mode, the operator's ListHTTPEndpoints and ListMCPServers APIs returned every HTTPEndpoint and MCPServer in the caller's namespace, including those scoped to other apps, with their Kubernetes secret references resolved to plaintext values.
GetConfiguration returned any Configuration in the namespace by name, with secret references in its OpenTelemetry headers resolved, whichever configuration the calling app was assigned.
ListResiliency, GetResiliency, ListSubscriptions and ListWorkflowAccessPolicy also ignored scopes. These APIs do not resolve or return secrets, so only the resource definitions were exposed.

Impact

Any workload able to get a Dapr workload identity for an app ID in a namespace, which includes every Dapr-enabled pod, could call the operator directly and read the credentials of HTTPEndpoint and MCPServer resources scoped to other apps in that namespace.
This covers header values such as Authorization tokens, client TLS certificates, private keys and root CAs, and MCP server headers and stdio environment variables.
It could also read secret OpenTelemetry headers of Configurations assigned to other apps.

Only values from the Kubernetes secret store (the default) were disclosed, because the operator resolves only those. Other namespaces were not exposed.
Sidecars already ignored resources not scoped to their app ID, so applications behaved correctly; the problem was what the operator sent.

Reported by Sathwik Yadlapati.

Root Cause

These operator APIs checked that the caller's identity was in the requested namespace, but did not compare the caller's app ID with each resource's scopes, as ListComponents and the resource update streams already did.
GetConfiguration trusted the configuration name sent by the sidecar.

Solution

The operator now skips resources whose scopes do not include the calling app ID before it resolves any secret, and GetResiliency reports them as not found.
GetConfiguration only returns the configuration named in the dapr.io/config annotation of one of the calling app's pods, and returns PermissionDenied otherwise. If the pod is not in the operator's cache yet, the operator reads it from the Kubernetes API.

A daprd you run in Kubernetes mode without the injector, with --config, must be in a pod with the dapr.io/enabled: "true", dapr.io/app-id and dapr.io/config annotations and the dapr.io/app-id label, and its container must be named daprd so the injector does not add a second one.
Otherwise the operator refuses the configuration and daprd fails to start.

Dapr Runtime v1.18.8

Choose a tag to compare

@dapr-bot dapr-bot released this 21 Oct 12:27
6539b81

Dapr 1.18.8

This update contains the following bug fixes and improvements:

Completed workflows created a reminder for every duplicate result

Problem

When an activity result or external event arrived again for a workflow that had already completed, the sidecar created a wake-up reminder for the workflow. The reminder fired and ran a workflow turn with nothing to process.

Impact

You were affected if you ran workflows whose activities could run more than once, for example after a sidecar restart or a placement change. After a fan-out workflow completed, each late duplicate result cost a reminder create in the Scheduler, a reminder fire and an actor turn.

Root Cause

The sidecar drops a result that is already in the workflow's history or inbox, and creates the wake-up reminder again in case the first one was lost. It did this for completed workflows too, although a completed workflow never processes its inbox again.

Solution

The sidecar acknowledges a duplicate result for a completed workflow without creating a reminder. A running workflow still gets its wake-up reminder.

Cancelled actor calls broke turn-based concurrency

Problem

When a caller cancelled an actor call that was waiting for the actor's current turn to finish, the sidecar could send other waiting calls to the app while that turn was still running. Several calls could then run at once on the same actor ID, with reentrancy enabled or disabled.

Impact

You were affected if callers of your actors cancel calls, for example through client timeouts or abandoned requests, while other calls to the same actor are waiting. Turns that read, modify and write actor state could run at the same time and overwrite each other's changes. Removing an actor timer while its call was waiting behind a running turn caused the same problem.

Root Cause

Each actor keeps a queue of calls waiting for its lock, and the running turn is at the front of that queue. When a waiting call was cancelled, it removed the front of the queue, which was the running turn, rather than its own entry. The next waiting call then started while the running turn was still executing.

Solution

Only the running turn removes calls from the queue. A call cancelled while waiting is marked as abandoned and skipped when the running turn finishes, so each actor runs one turn at a time again.

Sidecar stopped exporting trace spans after a hot reload restart

Problem

After hot reload restarted the sidecar's runtime, the sidecar exported no trace spans for as long as the process ran. Nothing was logged. Requests still succeeded and the sidecar still propagated trace context, so the application's spans named parent spans that never reached the tracing backend.

Impact

You were affected if you export traces with hot reload enabled, which is the default since 1.18.0. Hot reload restarts the runtime when a Configuration, HTTPEndpoint or Resiliency resource changes. In self-hosted mode, any file change in a resources directory that holds a Configuration also restarted it. Recreating the sidecar restored span export until the next restart. Versions 1.17 and earlier are not affected, because hot reload did not restart the runtime.

Root Cause

The sidecar and its workflow engine each looked up their tracer once, when the process started. OpenTelemetry binds those tracers to the first tracer provider the runtime registers. A hot reload restart shut that provider down and registered a new one, but the tracers stayed bound to the old provider, which had no exporter left.

Solution

The sidecar registers one tracer provider for the life of the process. It forwards every span to the tracer provider of the current runtime, so tracers looked up at startup keep exporting after a restart.

Redis components could not open new connections after the Entra ID token expired

Problem

With useEntraID: true, the Redis state store, pub/sub, binding, lock and configuration components worked until the first access token expired. After that, every new connection to Redis failed with WRONGPASS invalid username-password pair or user is disabled, and the component stayed broken until the sidecar was restarted.

Impact

You were affected if a Redis component authenticated to Azure Cache for Redis or Azure Managed Redis with Microsoft Entra ID. The first token lasts about an hour for a service principal and up to 24 hours for a managed identity. Once it expired, any connection the client opened afterwards failed to authenticate, whether the pool replaced an idle or aged connection, recovered from a network interruption, or grew under load. Reporters saw every call through the component fail after the first token's lifetime, until the pod was restarted.

Root Cause

At startup the component fetched one token and stored it as the connection password. The Redis client sends that stored password every time it opens a connection, so a connection opened after the token expired presented a token Redis no longer accepted. A background routine refreshed the token before it expired, but it only re-authenticated the single connection it ran on and never replaced the stored password.

Solution

The component fetches a current token every time it opens a Redis connection, so connections opened after the first token expires authenticate with a valid one.

Security: Compromised eMudhra intermediate CA keys were trusted for outbound TLS

Problem

The private keys of eight eMudhra intermediate CA certificates were compromised and reported to the browser root programs on October 17, 2026.
Anyone holding one of these keys can issue a TLS certificate for any domain that Go programs accept as valid.
Dapr 1.18.7 and earlier were built with Go 1.26.9, which still trusts certificate chains through these intermediates.

Impact

You were affected if daprd makes outbound TLS connections that are verified against the system trust store, such as components connecting to cloud services or service invocation to external HTTPEndpoints.
An attacker holding one of the keys and able to intercept that traffic could impersonate the remote service and read or change the data sent to it.
mTLS between sidecars and the control plane uses Dapr's own CA and is not affected.
According to the Chrome Root Program, no website certificate chaining to these intermediates had been logged to Certificate Transparency before they were blocked.

Root Cause

Go's crypto/x509 verifier does no revocation checks, so the compromised intermediates stayed trusted until Go itself blocked them.

Solution

Dapr is now built with Go 1.26.10, whose crypto/x509 package rejects any certificate chain that passes through the compromised keys.

Sidecar leaked a connection every second while the Scheduler was unreachable

Problem

While the sidecar could not reach any Scheduler host, it opened a new gRPC connection for each attempt to watch the Scheduler host list, about once a second, and never closed the connection when the attempt failed. Each leaked connection kept its goroutines and memory until the sidecar restarted.

Impact

You were affected if the Scheduler was unreachable from a sidecar for a sustained period, for example because its replicas were crash looping or their etcd volumes had run out of disk. The goroutine count and memory use of every sidecar grew for as long as the outage lasted. In the reported case, each sidecar accumulated several thousand leaked goroutines over two and a half days. Restarting the sidecar released them.

Root Cause

The sidecar opens a connection to a Scheduler host and then starts the WatchHosts stream on it. When starting the stream failed, the sidecar returned the error without closing the connection it had just opened, and the retry loop opened another one a second later.

Solution

The sidecar closes the connection when starting the WatchHosts stream fails, so each failed attempt releases its connection before the next one.

Dapr Runtime v1.17.18

Choose a tag to compare

@dapr-bot dapr-bot released this 21 Oct 23:27
37fb2fb

Dapr 1.17.18

This update contains the following security fix:

Security: Operator disclosed resources and secrets scoped to other apps

Problem

In Kubernetes mode, the operator's ListHTTPEndpoints API returned every HTTPEndpoint in the caller's namespace, including those scoped to other apps, with their Kubernetes secret references resolved to plaintext values.
GetConfiguration returned any Configuration in the namespace by name, with secret references in its OpenTelemetry headers resolved, whichever configuration the calling app was assigned.
ListResiliency, GetResiliency and ListSubscriptions also ignored scopes. These APIs do not resolve or return secrets, so only the resource definitions were exposed.

Impact

Any workload able to get a Dapr workload identity for an app ID in a namespace, which includes every Dapr-enabled pod, could call the operator directly and read the credentials of HTTPEndpoint resources scoped to other apps in that namespace.
This covers header values such as Authorization tokens, and client TLS certificates, private keys and root CAs.
It could also read secret OpenTelemetry headers of Configurations assigned to other apps.

Only values from the Kubernetes secret store (the default) were disclosed, because the operator resolves only those. Other namespaces were not exposed.
Sidecars already ignored resources not scoped to their app ID, so applications behaved correctly; the problem was what the operator sent.

Reported by Sathwik Yadlapati.

Root Cause

These operator APIs checked that the caller's identity was in the requested namespace, but did not compare the caller's app ID with each resource's scopes, as ListComponents and the resource update streams already did.
GetConfiguration trusted the configuration name sent by the sidecar.

Solution

The operator now skips resources whose scopes do not include the calling app ID before it resolves any secret, and GetResiliency reports them as not found.
GetConfiguration only returns the configuration named in the dapr.io/config annotation of one of the calling app's pods, and returns PermissionDenied otherwise. The operator reads the app's pods from the Kubernetes API, selected by the dapr.io/app-id label.

A daprd you run in Kubernetes mode without the injector, with --config, must be in a pod with the dapr.io/enabled: "true", dapr.io/app-id and dapr.io/config annotations and the dapr.io/app-id label, and its container must be named daprd so the injector does not add a second one.
Otherwise the operator refuses the configuration and daprd fails to start.