Skip to content

Dev Spec - Add generic exception-content redaction with WithExceptionScrubber#6094

Open
gladjohn wants to merge 2 commits into
mainfrom
gladjohn-patch-16
Open

Dev Spec - Add generic exception-content redaction with WithExceptionScrubber#6094
gladjohn wants to merge 2 commits into
mainfrom
gladjohn-patch-16

Conversation

@gladjohn

@gladjohn gladjohn commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

MSAL surfaces service/server error responses through exceptions, and applications commonly log those exceptions. If an exception's Message or raw ResponseBody contains sensitive token-like content, that content can end up in application logs or telemetry.

This PR adds a developer spec for a proposed MSAL .NET exception-content redaction mechanism. The spec is intended to be implementation-ready and AI/coding-agent friendly: it defines the proposed public API shape, internal redaction pipeline, compatibility constraints, edge cases, validation matrix, and follow-up implementation decisions.

No product code, public API, tests, or PublicAPI.Unshipped.txt changes are included in this PR. Those will be handled in follow-up implementation PRs.

What this developer spec proposes

The spec proposes a generic, partner-agnostic mechanism to redact sensitive token-like content from MSAL-owned exception content at creation, plus an always-on built-in baseline scrubber, while preserving diagnostic signals that downstream libraries rely on.

Proposed public API shape:

  • public delegate string MsalExceptionScrubber(string content);
  • WithExceptionScrubber(MsalExceptionScrubber scrubber) on BaseAbstractApplicationBuilder<T>, so public-client, confidential-client, and managed-identity applications all inherit it.
  • The builder hook returns the builder for fluent chaining.

Intended behavior and guarantees

The developer spec defines the following intended behavior:

  • Additive: registered host scrubbers run first; MSAL's built-in baseline runs last and cannot be disabled through the hook.
  • Composable: repeated registrations compose rather than replace previous scrubbers.
  • Fail-safe: a scrubber that throws or returns null falls back to the baseline path and never changes exception type, error code, status code, correlation ID, retryability, or control flow.
  • Creation-time redaction: MSAL-owned Message and ResponseBody content on service-derived exceptions is redacted when MSAL constructs the exception.
  • Scoped coverage: other renderings are covered only to the extent that they derive from redacted stored fields.
  • String rendering: a baseline-only final pass is proposed for outermost ToString() rendering.
  • Context-aware vs. context-free paths:
    • Context-aware service-response paths can use host scrubber + baseline.
    • Context-free paths such as broker, IMDS, managed identity, and throttling receive baseline-only protection unless later re-plumbed to carry configuration.
  • Preserved recovery data: claims challenges and recovery data are preserved and are not redacted.
  • Baseline rules are internal: built-in baseline patterns are implementation details and are not part of the public extensibility contract.

Downstream compatibility requirements

The spec treats downstream compatibility as load-bearing.

Redaction must preserve diagnostic routing signals that consumers branch on:

  • Redaction must not change MsalServiceException.ErrorCode.
  • Redaction must not remove or rewrite AADSTS* / AADB2C* protocol error-code tokens from in-scope redacted Message or ResponseBody content.
  • Built-in baseline rules must exclude protocol error/sub-error codes.
  • Redaction must not convert a non-null ResponseBody into null. Empty is allowed; null is not introduced by redaction.
  • Redaction must be surgical: only matched sensitive substrings are replaced, so routing codes elsewhere in the same content survive.

This is required to preserve Microsoft.Identity.Web control-flow, including:

  • certificate-retry routing on MsalServiceException.ErrorCode == invalid_client plus ResponseBody
  • B2C/password-reset routing on MsalUiRequiredException.Message

AI / coding-agent friendly structure

This spec is written so that follow-up implementation work can be fed to AI-assisted coding tools or implementation agents with minimal ambiguity.

It explicitly defines:

  • proposed public API surface
  • internal redaction pipeline ordering
  • context-aware and context-free behavior
  • failure behavior
  • null, empty, and whitespace handling
  • ResponseBody non-null compatibility
  • routing-token preservation requirements
  • ID.Web integration expectations
  • validation matrix
  • known exclusions
  • open questions that must be resolved before or during implementation

The intent is for a follow-up implementation PR to use this spec as the source of truth for code changes, tests, public API review, and release-note wording.

Expected follow-up implementation work

Follow-up PRs are expected to add:

  • MsalExceptionScrubber
  • WithExceptionScrubber(...)
  • configuration propagation through applicable request/application context paths
  • built-in baseline scrubber
  • creation-time redaction in MSAL-owned service exception construction paths
  • baseline-only handling for context-free paths
  • ToString() final-pass behavior, implemented without double-scrubbing
  • test coverage for the validation matrix
  • PublicAPI.Unshipped.txt updates
  • release-note documentation for the behavior change

Expected test coverage in follow-up PRs

The spec calls for tests covering:

  • registration on public-client, confidential-client, and managed-identity builders
  • redaction of Message and ResponseBody at creation
  • context-aware paths using host scrubber + baseline
  • context-free paths using baseline only
  • throwing scrubber fallback
  • null scrubber result fallback
  • empty required-message fallback to a generic non-empty message
  • non-null ResponseBody preservation
  • idempotency, including adversarial host scrubber plus baseline behavior
  • AADSTS* / AADB2C* routing-token preservation
  • certificate-retry compatibility
  • B2C/password-reset compatibility
  • ToString() baseline final pass
  • ToJsonString() behavior based on already-redacted stored fields
  • JSON rehydration not being claimed as a host-configured redaction path

Behavior change to document in implementation PR

When implemented, redaction at creation means Message and ResponseBody may return redacted text where they previously returned raw service content. The proposed baseline-only ToString() final pass may also alter string rendering.

This behavior change should be called out in release notes when the implementation ships.

Public API status

This PR does not add public API.

The developer spec proposes the following public API shape for review:

  • MsalExceptionScrubber
  • WithExceptionScrubber(MsalExceptionScrubber scrubber)

A follow-up implementation PR must update PublicAPI.Unshipped.txt with the exact entries produced by the repo analyzer.

Open questions

  • Should MSAL add an explicit routing-token preservation post-pass so the guarantee extends to arbitrary host scrubbers, not only MSAL-owned baseline and Microsoft-provided scrubbers?
  • Should the public scrubber remain string-only, or should it include field/source context?
  • Should context-free paths such as managed identity and broker be re-plumbed to carry app/request configuration in v1, or is baseline-only acceptable?
  • What placeholder format should the built-in baseline use?
  • Should serialized output later offer a diagnostic-safe mode that also redacts preserved recovery fields such as claims?

Document the design for generic exception-content redaction in MSAL .NET, outlining goals, principles, public API, built-in behavior, and integration with Microsoft.Identity.Web.
Copilot AI review requested due to automatic review settings June 27, 2026 22:12
@gladjohn gladjohn requested a review from a team as a code owner June 27, 2026 22:12

Copilot AI 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.

Pull request overview

Adds a design document describing a proposed MSAL.NET mechanism for redacting sensitive, token-like content from MSAL-owned exception Message / ResponseBody, including a host-provided scrubber hook and an always-on baseline scrubber to preserve downstream routing signals (e.g., AADSTS* / AADB2C*).

Changes:

  • Introduces a new design spec for exception-content redaction, including goals/non-goals, pipeline architecture, and failure-mode guarantees.
  • Documents proposed public API shape (MsalExceptionScrubber delegate + WithExceptionScrubber builder hook) and downstream compatibility constraints for Microsoft.Identity.Web.

Comment on lines +166 to +169
## 13. Compatibility and behavior change
- **Additive, net-new public surface:** one delegate type (`MsalExceptionScrubber`) and one builder method (`WithExceptionScrubber`). No breaking changes to existing APIs, no exception-type or error-code changes, no control-flow changes.
- **Behavior change to call out:** with redaction at creation, `Message` and `ResponseBody` may now return redacted text where they previously returned raw content; additionally, the baseline-only `ToString` final pass changes string rendering. Document in release notes.
- **Public API review** must include `PublicAPI.Unshipped.txt` updates for the `MsalExceptionScrubber` delegate and the `WithExceptionScrubber` method. The exact entries are determined by the repo tooling. Whether any baseline redaction patterns are exposed as public API is a separate decision (see Open questions); otherwise the baseline rules remain implementation details.
@gladjohn gladjohn changed the title Design - Add generic exception-content redaction (WithExceptionScrubber) with an always-on baseline  Dev Spec - Add generic exception-content redaction with WithExceptionScrubber Jun 28, 2026
Copilot AI review requested due to automatic review settings June 28, 2026 12:48

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment on lines +39 to +41
- Input: a piece of MSAL-owned exception content (a message or a response body).
- Output: redacted content, or the original content if no redaction is needed.
- Contract: may be called multiple times; should be thread-safe, deterministic, idempotent; must not assume a format (plain text vs JSON); should not throw — if it throws, MSAL treats that as scrubber failure and continues with the baseline; **should preserve diagnostic routing tokens (see Section 12).**
Comment on lines +43 to +46
**Builder hook:**
```csharp
WithExceptionScrubber(MsalExceptionScrubber scrubber) -> T
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants