Skip to content

SEC-768: Send card details to Stripe in the request body, not the URL - #380

Closed
msuitcase wants to merge 1 commit into
masterfrom
security/SEC-768-stripe-card-details-in-body
Closed

msuitcase wants to merge 1 commit into
masterfrom
security/SEC-768-stripe-card-details-in-body

Conversation

@msuitcase

@msuitcase msuitcase commented Sep 18, 2026 •

Copy link
Copy Markdown

Description

ReferralCustomerService.createStripeToken builds the POST https://api.stripe.com/v1/tokens request with card[number], card[exp_month], card[exp_year] and card[cvc] appended to the URL query string. It calls setDoOutput(true) but never writes a body. Query strings are routinely captured by access logs, outbound proxies, APM/tracing tools and Referer headers, so cardholder data could be retained outside the payment path (PCI DSS requirement 3 / 4).

This change writes the same form-encoded string to the connection's output stream and drops it from the URL. Stripe already expects application/x-www-form-urlencoded bodies on this endpoint (it is what easypost-ruby, easypost-go and easypost-csharp do today), so there is no behavioural change for callers. InternalUtilities.getEncodedURL is reused unchanged as the encoder.

Also adds a Next Release CHANGELOG entry.

Tracking: SEC-768 (internal).

Testing

  • No Maven on the machine I authored this from, so this has not been compiled here; the change is a new java.io.OutputStream import, one renamed local, and a try-with-resources write. Please run mvn test / checkstyle in CI.
  • Cassette re-record needed: src/test/cassettes/referral_customer/referral_add_credit_card.json and create_bad_stripe_token.json were recorded with the card fields in the URL, and TestUtils configures EasyVCR to match byFullUrl().byBody(...), so testReferralAddCreditCard and testCreateBadStripeToken will not replay until re-recorded with the partner / referral prod keys. I do not have those keys. When re-recording, please confirm the recorded URL no longer carries card fields and that the body censor rules cover card[number] and card[cvc].

Pull Request Type

Please select the option(s) that are relevant to this PR.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Improvement (fixing a typo, updating readme, renaming a variable name, etc)

🤖 Generated with Claude Code

`referralCustomer.addCreditCardToUser` built the `POST /v1/tokens` request
with the card number, expiry and CVC in the URL query string and never wrote
a request body (despite `setDoOutput(true)`). Stripe accepts the same
form-encoded fields in the request body, which keeps cardholder data out of
access logs, proxy logs, tracing tools and Referer headers.

SEC-768

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@msuitcase

Copy link
Copy Markdown
Author

Closing without merging. Moving the card fields into the request body does not restore this flow, so we are deprecating addCreditCard in favour of addCreditCardFromStripe with Stripe-hosted card collection. That work is tracked internally.

@msuitcase msuitcase closed this Sep 24, 2026
@msuitcase
msuitcase deleted the security/SEC-768-stripe-card-details-in-body branch September 24, 2026 16:30
@Justintime50

Copy link
Copy Markdown
Member

Closing due to #380

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