Skip to content

fix: sanitize span events and links, not just span attributes - #56

Merged
PabloPardoGarcia merged 1 commit into
mainfrom
pablo/rius-380-events-links-content-leak
Aug 12, 2026
Merged

fix: sanitize span events and links, not just span attributes#56
PabloPardoGarcia merged 1 commit into
mainfrom
pablo/rius-380-events-links-content-leak

Conversation

@PabloPardoGarcia

Copy link
Copy Markdown
Member

Closes the RIUS-380 privacy gap: MaskingSpanExporter._sanitized() read span.attributes and nothing else, so content in event attributes, link attributes, and record_exception's provider-echoed error strings exported verbatim even under capture_content=False or a mask. Route 1 needs no unusual instrumentation: any provider 400 that echoes the rejected request produces an exception event carrying the user's prompt.

Changes

  • _sanitize_mapping() extracted from the attributes path and applied uniformly to span.attributes, span.events[].attributes, and span.links[].attributes on both the strip and mask paths. Unchanged collections are returned as-is (no copies on the no-op path).
  • Exception policy (matching the TypeScript SDK's ruling): under capture_content=False, exception.message and exception.stacktrace are dropped while the exception event and exception.type stay, so failures remain visible and classifiable.
  • One decision to review: the ticket's TS ruling covers capture_content=False only; for the mask path I chose to apply the mask to exception.message/exception.stacktrace as well, because a PII scrubber that skips provider-echoed prompts in error strings re-creates exactly this bug for mask users. If the TS implementation decided otherwise, flag it and I'll align.

Tests

Six new tests pinning the boundary, not the collection: content in event attributes (strip + mask), content in link attributes, the exception pair under both paths, and the pass-through case (capture on, no mask) proving events stay untouched. Per the ticket's closing note, the existing tests all asserted on span.attributes and shared the defect's blind spot; these are the first to assert on events and links.

Suite: 205 passed; ruff, format, mypy strict clean.

RIUS-380

MaskingSpanExporter read span.attributes alone, so content in event
attributes (OTel GenAI's event-based shape), link attributes, and
record_exception's provider-echoed error strings exported verbatim
under capture_content=False or a mask.

- content keys in event and link attributes now go through the same
  strip/mask machinery as span attributes
- exception events: capture_content=False drops exception.message and
  exception.stacktrace but keeps the event and exception.type, so
  failures stay visible and classifiable (TypeScript SDK policy); a
  mask is applied to both keys
- six new tests pin events, links, the exception pair on both paths,
  and the untouched pass-through
@PabloPardoGarcia
PabloPardoGarcia merged commit 2caa7f1 into main Aug 12, 2026
8 checks passed
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.

1 participant