Skip to content

Stripe secret key leaked into the SPA payload (toUiPayload) #1148

Description

@Zwiterrion

Severity: 🔴 Critical (security)

The Stripe secret API key is shipped to the browser inside the SPA bootstrap payload.

Root cause

StripeSettings.toUiPayload tries to strip secrets but removes the wrong field name:

// daikoku/app/fr/maif/daikoku/domain/tenantEntities.scala:400-403
override def toUiPayload: JsValue =
  json.StripeSettingsFormat.writes(this).as[JsObject] ++ Json.obj("type" -> "Stripe")
    - "publicKey" - "privateKey"   // field is named "secretKey", not "privateKey"
  • StripeSettingsFormat.writes serializes secretKey (json.scala:4912-4918).
  • - "privateKey" is a no-op because no such key exists → secretKey stays in the payload (and the public key is removed instead).
  • Tenant.toUiPayload(env) embeds these settings unconditionally (tenantEntities.scala:554-556).
  • That payload is served to the browser in the SPA bootstrap, including the unauthenticated login page (HomeController.scala:240, LoginController.scala:1129).

For comparison, OtoroshiSettings.toUiPayload only returns id/url/host (tenantEntities.scala:677) — masking was clearly the intent here.

Impact

For any tenant with Stripe configured, the live secret key is readable by any visitor (page source / network tab). Full Stripe account compromise (charges, refunds, customer data).

Fix

  • Change the strip to - "secretKey" (keep publicKey, which is public).
  • Verify the rendered tenant_data no longer contains secretKey.
  • Rotate the exposed Stripe secret key(s).

How to verify

Start Daikoku with a tenant that has StripeSettings, load the unauthenticated login page, inspect the tenant_data bundle → secretKey must be absent.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsecurity

Type

Fields

No fields configured for Bug.

Projects

Status
Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions