Skip to content

[PM-42473] Use SSRF protected HttpClient in Teams service - #8334

Open
lastbestdev wants to merge 6 commits into
mainfrom
PM-42473/dirt/org-integration-ssrf-fix
Open

[PM-42473] Use SSRF protected HttpClient in Teams service#8334
lastbestdev wants to merge 6 commits into
mainfrom
PM-42473/dirt/org-integration-ssrf-fix

Conversation

@lastbestdev

@lastbestdev lastbestdev commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-42473

📔 Objective

The TeamsService internally creates a ConnectorClient that it uses to send messages to MS Teams channels. This ConnectorClient uses its own HttpClient when one is not provided, which did not use the SSRF protections that are applied to our server's custom HttpClient. This updates the TeamsService to provide the correct HttpClient with SSRF protections.

📸 Screenshots

N/A

@lastbestdev
lastbestdev requested a review from a team as a code owner September 9, 2026 21:35
@lastbestdev
lastbestdev requested a review from Banrion September 9, 2026 21:35
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR routes TeamsService.SendMessageToChannelAsync through the SSRF-protected named HttpClient by passing it to ConnectorClient with disposeHttpClient: false, so the stored (bot-supplied) ServiceUrl is now validated by SsrfProtectionHandler instead of being fetched by the SDK's own unprotected client. I verified the shared client is not disposed by the using on ConnectorClient, that the OAuth and Graph calls in this service already used the protected client, and that no other unprotected ConnectorClient/HttpClient remains on the Teams send path. The ModelState gate added to UpdateAsync mirrors CreateAsync, and the resulting rejection of Slack/Teams updates does not break their flows — both are provisioned through their OAuth/bot-install controllers and their event mappings live on the integration configuration endpoint, which is unaffected. New unit tests cover injection, non-disposal across repeated calls, and error propagation.

Code Review Details
  • 🎨 : Captured request body in the new test is never asserted on; spend it on a URI/payload assertion or drop it
    • test/Core.Test/Dirt/Services/TeamsServiceTests.cs:190

Comment thread test/Core.Test/Dirt/Services/TeamsServiceTests.cs Outdated
@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.98%. Comparing base (b89568d) to head (db73b41).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8334      +/-   ##
==========================================
- Coverage   64.03%   63.98%   -0.05%     
==========================================
  Files        2473     2471       -2     
  Lines      106017   105809     -208     
  Branches     9613     9595      -18     
==========================================
- Hits        67886    67703     -183     
+ Misses      35771    35756      -15     
+ Partials     2360     2350      -10     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lastbestdev lastbestdev added the t:bugfix Change Type - Bugfix label Sep 9, 2026
[HttpPost("")]
public async Task<ActionResult<OrganizationIntegrationResponseModel>> CreateAsync(Guid organizationId, [FromBody] OrganizationIntegrationRequestModel model)
{
if (!ModelState.IsValid)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is removed because it is redundant. .NET web API projects automatically run model validation logic when implemented (i.e. model implements IValidatableObject)

Therefore, the UpdateAsync method is actually running the validation logic as we expect, as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:bugfix Change Type - Bugfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant