Skip to content

[PM-41693] Align error behavior when Send is not accessible - #8229

Open
harr1424 wants to merge 2 commits into
mainfrom
tools/PM-41693-align-error-behavior-when-send-cannot-be-accessed
Open

[PM-41693] Align error behavior when Send is not accessible #8229
harr1424 wants to merge 2 commits into
mainfrom
tools/PM-41693-align-error-behavior-when-send-cannot-be-accessed

Conversation

@harr1424

Copy link
Copy Markdown
Contributor

🎟️ Tracking

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

📔 Objective

This PR improves user experience by standardizing the server's response when a Send should not be accessed (a non-exhaustive list is in the section below). These changes come at the expense of guarding against enumeration in the event that a Send had been deliberately deleted; formerly this situation would result in one of three random error messages.

The following behavior was flagged as a defect:

  • One of the random error responses indicated the Send required password authentication, this was surfaced to the user as password_hash_b64_required

  • A different random error response would result in an infinite OTP auth flow

Internal product teams requested changes to align error behavior whenever a Send should not be accessible (see list below).

📸 Screenshots

Screenshot 2026-08-18 at 18 07 55

The above message will be shown in ALL of the following situations:

  • A Send has been deliberately deleted
  • A Send has passed it's configured deletion date
  • A Send has passed it's configured expiration date
  • A Send is disabled
  • A Send has exceeded it's configured max access count

@harr1424
harr1424 requested review from a team as code owners August 19, 2026 01:29
@harr1424
harr1424 requested a review from rr-bw August 19, 2026 01:29
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR collapses the NeverAuthenticate Send authentication method into SendInaccessible, so a missing send_id now returns the same invalid_grant / send_id_invalid response as a disabled, expired, deleted, or max-access-exceeded Send. The removal remains complete and consistent: no references to NeverAuthenticate, SendAccessConstants.EnumerationProtection, or GlobalSettings.SendDefaultHashKey survive anywhere in src/, test/, util/, or deployment templates; the DI registration was dropped and the SendAccess readme updated. EnumerationProtectionHelpers is correctly left in place since AccountsController still uses it, SendConstantsSnapshotTests is unaffected because no SDK-shared constant values changed, and dropping the SendDefaultHashKey property is safe for self-hosted instances that still set it since nothing in the repo enables strict configuration binding.

The latest commit adds two end-to-end tests (SendAccessGrant_ExistingAccessibleSend_ReturnsAccessToken and SendAccessGrant_DeletedSend_ReturnsInvalidGrant) that exercise the real SendAuthenticationQuery and SendAccessGrantValidator with only ISendRepository substituted — this is the right seam for the behavior being changed, and it directly covers the null-Send path that previously routed through the deleted validator. The (Send?)null cast is fine given test projects build with Nullable=annotations, and the singleton repository substitute registered via WithWebHostBuilder correctly takes precedence over the scoped EF registration.

Code Review Details

No new findings.

The previously raised question about the removal of the Send enumeration protection was answered by the author with the internally tracked ticket PM-41693, so it is not reopened here.

@harr1424 harr1424 added bug needs-qa ai-review Request a Claude code review t:bugfix Change Type - Bugfix labels Aug 19, 2026
SendAuthenticationMethod method = send switch
{
null => NEVER_AUTHENTICATE,
null => SEND_INACCESSIBLE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

QUESTION: Was the removal of the Send enumeration protection reviewed with the security team?

Context

This change (plus the deletion of SendNeverAuthenticateRequestValidator and GlobalSettings.SendDefaultHashKey) removes a control that was deliberately added to prevent distinguishing a non-existent send_id from one that exists and requires auth. After this PR, an unknown send_id deterministically returns invalid_grant / send_id_invalid, while an existing, accessible, password- or OTP-protected Send returns password_hash_b64_required / email_required — so the two states become reliably distinguishable.

The PR description acknowledges the trade-off, and the residual risk looks low given Send IDs are 122 bits of randomness (offline enumeration is infeasible; the practical leak is limited to someone who already holds a link learning whether the Send is still live). Asking mainly so the sign-off is recorded on the PR — was AppSec looped in, given this reverses an explicitly documented anti-enumeration measure?

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.

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.27%. Comparing base (f5e940c) to head (a764ecc).
⚠️ Report is 13 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8229      +/-   ##
==========================================
- Coverage   63.30%   63.27%   -0.03%     
==========================================
  Files        2383     2400      +17     
  Lines      103898   103986      +88     
  Branches     9402     9421      +19     
==========================================
+ Hits        65771    65802      +31     
- Misses      35883    35929      +46     
- Partials     2244     2255      +11     

☔ 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.

@rr-bw
rr-bw requested review from ike-kottlowski and removed request for rr-bw August 19, 2026 19:15
Comment on lines +126 to +129
var requestBody = new FormUrlEncodedContent([
new KeyValuePair<string, string>(OidcConstants.TokenRequest.GrantType, CustomGrantTypes.SendAccess),
new KeyValuePair<string, string>(OidcConstants.TokenRequest.ClientId, BitwardenClient.Send)
]);

@ike-kottlowski ike-kottlowski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just the comment about notifying SRE of the globalsettings shape change.

Comment on lines -99 to -102
/// <summary>
/// This Hash Key is used to prevent enumeration attacks against the Send Access feature.
/// </summary>
public virtual string SendDefaultHashKey { get; set; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ : We need to communicate to SRE that this value is no longer needed in our upper environs.

We want to make sure we're keeping our settings files lean so we will want to remove this setting.

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

Labels

ai-review Request a Claude code review bug needs-qa t:bugfix Change Type - Bugfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants