fix(basket): redact sensitive params and keep query separators in batched outgoing link hrefs

Aperta Adatta ai principianti
#1,143 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

@ANSHSINGH050404 ci sta già lavorando.

Dal 19/10/2026.

  • #1144 di @ANSHSINGH050404 — aperta

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
84/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
bun, typescript
Ambito
backend

Direzione di ricerca

Leggi apps/basket/src/routes/basket.ts intorno a processOutgoingLinkData e confronta la gestione di href con apps/basket/src/lib/event-service.ts intorno a insertOutgoingLink. Inizia dalle utilità di convalida in apps/basket/src/utils/validation.ts; l’issue propone di usare sanitizeUrl per l’href del batch. Il lavoro è completato quando i link del batch mantengono i separatori della query e oscurano i valori sensibili della query come il percorso del singolo evento.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Problem

POST /batch stores outgoing-link href values with a different sanitizer than every other outgoing-link write path. POST / and GET /px.jpg use sanitizeUrl; the batch path uses sanitizeString.

The two differ in two ways that matter:

  1. sanitizeString strips & (it removes < > ' " &), so query parameters fuse together: ?utm_source=x&plan=pro is stored as ?utm_source=xplan=pro. The recorded outgoing-link destination is wrong and per-parameter attribution breaks.
  2. sanitizeString does not redact sensitive query parameters, so token, email, password, api_key, otp, credit_card and the other keys in SENSITIVE_QUERY_PARAMS are written verbatim into analytics.outgoing_links.href. The single-event path stores REDACTED for the same payload.
POST /batch  ->  https://partner.example/click?a=1b=2token=secret
POST /       ->  https://partner.example/click?a=1&b=2&token=REDACTED

This is the same defect class fixed for the other paths in #1135 ("keep & in sanitized URLs so query parameters stay separate") and #1136 ("redact sensitive params in hash-routed URL fragments"); the batch path was left behind.

Root cause

apps/basket/src/routes/basket.ts:144 (processOutgoingLinkData) calls sanitizeString(linkData.href, ...). apps/basket/src/lib/event-service.ts:365 (insertOutgoingLink, used by POST / and GET /px.jpg) calls sanitizeUrl(linkData.href, ...).

In apps/basket/src/utils/validation.ts:

  • sanitizeString uses UNSAFE_CHARS_REGEX = /[<>'"&]/g — strips &, no redaction.
  • sanitizeUrl uses URL_UNSAFE_CHARS_REGEX = /[<>'"]/g — preserves &, and applies redactSensitiveQueryParams first.

Every other URL-bearing field in the service — track referrer/url/path, vitals, errors, custom events, engagement spans, blocked traffic — already uses sanitizeUrl. The batch outgoing-link href is the only divergence.

To reproduce

bun -e "const {sanitizeString, sanitizeUrl} = await import('./apps/basket/src/utils/validation.ts');
const h='https://partner.example/click?a=1&b=2&token=secret&[email protected]';
console.log('batch (sanitizeString):', sanitizeString(h,2048));
console.log('single(sanitizeUrl)   :', sanitizeUrl(h,2048));"
batch (sanitizeString): https://partner.example/[email protected]
single(sanitizeUrl)   : https://partner.example/click?a=1&b=2&token=REDACTED&email=REDACTED

At the route level, POST /batch with a body of:

[
  {
    "type": "outgoing_link",
    "eventId": "evt_link_1",
    "href": "https://partner.example/click?a=1&b=2&token=secret",
    "text": "Partner"
  }
]

stores href = "https://partner.example/click?a=1b=2token=secret", while the identical payload on POST / stores "https://partner.example/click?a=1&b=2&token=REDACTED".

Proposed fix

Use sanitizeUrl for the batch outgoing-link href, matching every other outgoing-link write path:

-			href: sanitizeString(linkData.href, VALIDATION_LIMITS.PATH_MAX_LENGTH),
+			href: sanitizeUrl(linkData.href, VALIDATION_LIMITS.PATH_MAX_LENGTH),

No new abstraction and no behavior change to any other field.

Scope note

The first-party browser tracker posts outgoing links to POST / (packages/tracker/src/plugins/outgoing-links.ts:37), so the shipped tracker is unaffected today. The defect hits direct POST /batch consumers — the endpoint's own public surface — and would silently widen if any SDK path starts batching outgoing links.

Rows already written stay as they are. No migration is proposed, since analytics.outgoing_links is an append-only analytics table.

AI usage disclosure

I used OpenCode

Lingua principale
TypeScript
Stelle
1.2k
Fork
227
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.