Skip to content

fix(pii): redact card authorization codes and brand+last4 in Sabre remarks - #80

Closed
armona wants to merge 1 commit into
masterfrom
fix/card-authorization-remarks
Closed

fix(pii): redact card authorization codes and brand+last4 in Sabre remarks#80
armona wants to merge 1 commit into
masterfrom
fix/card-authorization-remarks

Conversation

@armona

@armona armona commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Why

Follow-up to #79. You asked whether the payloads carried credit-card data and whether it was
anonymized. Rather than answer from the earlier analysis alone, I audited every fixture for both
channels — redacting each through the real engine with the per-channel operation parser the forwarder
uses, then scanning the output for card shapes (masked PAN, bare PAN, expiry, CVV, approval codes,
<brand><last four>).

Result: card numbers are covered everywhere, including the Travelfusion CreditCard block
(Number, SecurityCode, ExpiryDate all tokenized) and the Sabre/Amadeus card elements. But card
authorization lines leak two other pieces of payment data:

Rendering Operation Leaked before
XXAUTH/<approval> *Z/<brand><last4> GetReservationRS both — untouched entirely
CC APVL/<approval>/TKT/<carrier>/<brand><last4> GetReservationRS both — untouched entirely
AUTH-APV/<approval>/000/USD… Trip_SearchRS approval code
XXAUTH/<approval>/<masked PAN>/… Trip_SearchRS approval code
AUTH-AMEX/<brand><last4>/… Trip_SearchRS already covered

GetReservationRS is the operation the original customer report was about, and it was leaking the
last four digits of the card plus the acquirer approval code in cleartext.

This is an inconsistency rather than a new policy call: the baseline already classifies both as
payment data — amadeus.transaction.payment redacts approvalCode, and
sabre.etkt.payment_approval masks @ApprovalID. Only the reservation and trip-search remark
renderings were uncovered.

What changed

Three rules, all one-way replace per the existing payment action policy, all anchored on the
literal AUTH / CC APVL markers:

  • sabre.res.auth_approval_code — approval code in the three renderings, across the remark path and
    both history mirrors.
  • sabre.res.auth_card_fragment<brand><last four> in the AUTH and CC APVL forms.
  • sabre.trip.auth_approval_code — approval code on Trip_SearchRS.

Preserved deliberately: the AUTH-/XXAUTH//CC APVL/ markers, amounts (USD423.20,
USD388.90 - USED), dates, carrier codes (/TKT/DL/), the AUTH-AVS NOT SUPPORTED and
AUTH-CSC NOT SUPPLIED status lines, and the card brand word on its own — a brand alone is not
sensitive; the last four beside it is.

Testing

TestCardAuthorizationRemarks — 3 tests covering both GetReservationRS renderings, the
Trip_SearchRS approval code and fragments, and the operational-text negatives. Written failing
first; 2 of 3 failed before the rules landed.

Re-ran the full card audit afterwards: zero real survivors across all fixtures for all five
channels. 695 tests pass.

Note, not a defect

Travelfusion encrypts the card Number and SecurityCode (CVV) reversibly, where Sabre/Amadeus use a
one-way sentinel. That asymmetry looks deliberate — the relay must hand the real values to the
supplier on the request path to complete a booking — so I left it alone. Flagging it in case you want
that revisited separately.

🤖 Generated with Claude Code

…marks

An audit of every fixture for surviving card data found authorization lines leaking
two pieces of payment data beyond the PAN: the acquirer approval code and a
<brand><last four> fragment.

GetReservationRS was the worst case — "XXAUTH/<approval> *Z/<brand><last4>" and
"CC APVL/<approval>/TKT/<carrier>/<brand><last4>" passed through completely untouched,
leaking the last four digits of the card on the operation a customer had reported.
Trip_SearchRS already covered the card fragment via sabre.trip.card_fragment_remark
but left the approval code ("AUTH-APV/<code>", "XXAUTH/<code>") in the clear.

Both are already classified as payment data elsewhere in the baseline —
amadeus.transaction.payment redacts approvalCode and sabre.etkt.payment_approval masks
@ApprovalID — so the reservation and trip-search remark forms were an inconsistency,
not a new policy call. Redacted one-way, matching the existing payment action policy.

Markers, amounts, dates, carrier codes and the status lines that carry no card data are
preserved, as is the card brand word on its own; only the last four beside it is
sensitive. Patterns stay anchored on the literal AUTH/APVL markers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@armona armona closed this Aug 13, 2026
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