From 4835223a0a3ac5bea2a75ee6fb43306d9f986e4d Mon Sep 17 00:00:00 2001 From: msuitcase <97645156+msuitcase@users.noreply.github.com> Date: Fri, 18 Sep 2026 01:31:43 -0700 Subject: [PATCH] Send card details to Stripe in the request body, not the URL `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 --- CHANGELOG.md | 4 ++++ .../com/easypost/service/ReferralCustomerService.java | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc6bc464f..c0a6ca856 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## Next Release + +- Sends card details in the request body instead of the URL query string when `referralCustomer.addCreditCardToUser` creates a Stripe token + ## v8.8.0 (2026-06-25) - Adds `params` to `requestPin` ensuring users can pass `easypost_details` to the call diff --git a/src/main/java/com/easypost/service/ReferralCustomerService.java b/src/main/java/com/easypost/service/ReferralCustomerService.java index e21f2320f..721284cac 100644 --- a/src/main/java/com/easypost/service/ReferralCustomerService.java +++ b/src/main/java/com/easypost/service/ReferralCustomerService.java @@ -18,6 +18,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -257,8 +258,10 @@ private static String createStripeToken(final String number, final int expiratio params.put("exp_year", String.valueOf(expirationYear)); params.put("cvc", cvc); - String encodedURL = InternalUtilities.getEncodedURL(params, "card"); - URL stripeUrl = new URL("https://api.stripe.com/v1/tokens?" + encodedURL); + // Card details must travel in the form-encoded request body, never in the URL, + // so they cannot end up in access logs, proxy logs, or Referer headers. + String encodedBody = InternalUtilities.getEncodedURL(params, "card"); + URL stripeUrl = new URL("https://api.stripe.com/v1/tokens"); HttpURLConnection conn; if (EasyPost._vcrUrlFunction != null) { @@ -272,6 +275,10 @@ private static String createStripeToken(final String number, final int expiratio conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setDoOutput(true); + try (OutputStream outputStream = conn.getOutputStream()) { + outputStream.write(encodedBody.getBytes(StandardCharsets.UTF_8)); + } + StringBuilder response; try (BufferedReader br = new BufferedReader(