AI-generated audit finding — this issue was opened from an automated security/correctness audit. It has not been triaged by a human yet; verify the reasoning, reproducibility, and severity before acting on it.
Medium: request-scoped services are disposed before response payload emission completes — CONFIRMED
Affected code:
Verification:
Confirmed. DispatcherBuilder.Build() wraps _router.DispatchAsync in an await using ConfiguredAsyncDisposable over a fresh AsyncServiceScope. The scope is released the moment the dispatcher lambda awaits past the DispatchAsync call and returns the OutgoingResponse — which happens before the protocol connection drains response.Payload onto the wire. Concretely, the icerpc path issues payloadWriter.CopyFromAsync(response.Payload, ..., _disposedCts.Token) at IceRpcProtocolConnection.cs:1101, well after the scope's DisposeAsync has run.
Any response.Payload that lazily pulls from a scoped service (the typical pattern for streamed replies backed by EF Core, a scoped HttpClient, etc.) will encounter a disposed dependency partway through transmission.
Impact:
- Streamed responses can fail mid-body with
ObjectDisposedException wrapped as InternalError on ice, or truncated reply on icerpc after headers have been sent.
- User code gets no clear diagnostic linking the failure back to the DI scope lifetime.
Recommendation:
- Hold the scope open until response payload emission completes. The cleanest implementation is a decorator on
response.Payload whose Complete method disposes the scope, replacing the current await using.
- Alternatively, document and enforce that scoped services must not back deferred response payload producers.
- Add regression tests with response payloads backed by scoped disposable services.
Status: Valid, Medium severity.
Source report: src-IceRpc.Extensions.DependencyInjection-audit-2026-04-14.md (finding request-scoped services are disposed before response payload emission completes — **CONFIRMED**)
Severity (auditor-assigned): Medium
Medium: request-scoped services are disposed before response payload emission completes — CONFIRMED
Affected code:
await usingwhen_router.DispatchAsyncreturnsawait PerformDispatchRequestAsync(...)completespayloadWriter.CopyFromAsync(response.Payload, ...)runs after the dispatcher lambda has returned and its scope has been disposedicesideVerification:
Confirmed.
DispatcherBuilder.Build()wraps_router.DispatchAsyncin anawait using ConfiguredAsyncDisposableover a freshAsyncServiceScope. The scope is released the moment the dispatcher lambda awaits past theDispatchAsynccall and returns theOutgoingResponse— which happens before the protocol connection drainsresponse.Payloadonto the wire. Concretely, the icerpc path issuespayloadWriter.CopyFromAsync(response.Payload, ..., _disposedCts.Token)at IceRpcProtocolConnection.cs:1101, well after the scope'sDisposeAsynchas run.Any
response.Payloadthat lazily pulls from a scoped service (the typical pattern for streamed replies backed by EF Core, a scoped HttpClient, etc.) will encounter a disposed dependency partway through transmission.Impact:
ObjectDisposedExceptionwrapped asInternalErroronice, or truncated reply onicerpcafter headers have been sent.Recommendation:
response.PayloadwhoseCompletemethod disposes the scope, replacing the currentawait using.Status: Valid, Medium severity.
Source report: src-IceRpc.Extensions.DependencyInjection-audit-2026-04-14.md (finding
request-scoped services are disposed before response payload emission completes — **CONFIRMED**)Severity (auditor-assigned): Medium