billing: escape the DID before interpolating it into a Stripe search

findCustomerByDID built its search query with fmt.Sprintf, so the DID was
interpolated into a quoted Stripe search string unescaped. DIDs arriving
here are OAuth-validated and the DID grammar forbids quotes, so this is
not currently exploitable, but the query's safety depended on a validator
several layers away rather than on anything visible at the call site.

Escape backslash and single quote the way Stripe's search grammar
specifies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Evan Jarrett
2026-08-09 20:51:31 -05:00
co-authored by Claude Opus 5
parent fa1dfb04f6
commit cecb8879de
+6 -1
View File
@@ -658,9 +658,14 @@ func (m *Manager) getOrCreateCustomer(userDID, userHandle string) (*stripe.Custo
// findCustomerByDID searches Stripe for a customer with matching DID metadata.
func (m *Manager) findCustomerByDID(userDID string) (*stripe.Customer, error) {
// DIDs reaching here are OAuth-validated (the DID grammar forbids quotes),
// but escape defensively so the query's safety doesn't silently depend on a
// validator several layers away. Stripe search escapes ' and \ with a
// backslash.
escaped := strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(userDID)
params := &stripe.CustomerSearchParams{
SearchParams: stripe.SearchParams{
Query: fmt.Sprintf("metadata['user_did']:'%s'", userDID),
Query: fmt.Sprintf("metadata['user_did']:'%s'", escaped),
},
}