|
Task Description
Severity: Medium CVSS: 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L) Endpoint: GET https://www.alwaysdata.com/en/signup/token/ Method: GET Auth Required: None (verified) Rate Limited: No (verified — 20+ requests with no throttle)
Unauthenticated Generation of Production PayZen Payment Tokens Enables Denial of Wallet
Summary The endpoint GET /en/signup/token/ generates production-mode PayZen payment form tokens with no authentication and no rate limiting. Each request creates a unique merchant session in alwaysdata's PayZen account. An attacker can generate unlimited tokens in a tight loop, potentially exhausting alwaysdata's PayZen API quota, flooding their payment dashboard with phantom registration sessions, or causing billing issues with their payment processor.
Steps to Reproduce
1. Generate a token without any authentication:
curl -sk https://www.alwaysdata.com/en/signup/token/
-> {"token": "01uJrqyaukSA2FyhTy..."} [HTTP 200, no auth required]
2. Decode the token to confirm PRODUCTION mode:
python3 -c "
import base64, json
token = '01uJrqy...265eyJhbW91bnQ...'
json_b64 = token[token.find('eyJ'):]
decoded = base64.b64decode(json_b64 + '==').decode('utf-8', errors='replace')
print(json.dumps(json.loads(decoded[:decoded.rfind('}')+1]), indent=2))
"
-> {
"amount": 0,
"currency": "EUR",
"mode": "PRODUCTION",
"orderId": "TKN98661",
"shopName": "ALWAYSDATA",
"formAction": "REGISTER",
"customerEmail": "contact@alwaysdata.com",
"jSessionId": "59B9cAcaaD76C7fe9dEEbdD1D3FF86E3d95CAaBd.vadapi01-tls-prod-fr-lyra"
}
3. Confirm no rate limiting by generating multiple tokens in rapid succession:
for i in $(seq 1 10); do
curl -sk https://www.alwaysdata.com/en/signup/token/ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['token'][:30])"
done
-> All 10 requests return distinct tokens with different orderIds and jSessionIds
(no 429, no CAPTCHA, no rate limiting observed at 10+ req/s)
Key Findings from Decoded Token - mode: PRODUCTION (not sandbox/test) — tokens interact with live PayZen infrastructure - amount: 0 EUR, formAction: REGISTER — these are card-registration tokens, not payment - orderId increments each request (e.g., TKN98660, TKN98661, TKN98662…) — confirms unique sessions created server-side - jSessionId exposes internal PayZen load-balancer node names (vadapi01-tls-prod-fr-lyra, vadapi02-tls-prod-fr-lyra) - customerEmail hardcoded as contact@alwaysdata.com (not user-supplied — no PII exposure)
Impact
1. Denial of Wallet (DoW): PayZen API calls are metered by merchant account. Flooding /en/signup/token/ generates real merchant sessions that count against alwaysdata's PayZen quota. If PayZen applies per-session fees or rate limits at the merchant level, this could cause service disruption or unexpected costs.
Estimated rate: 20+ sessions/second possible (no server-side limiting observed)
PayZen pricing: typically per-transaction or per-session depending on contract
2. Merchant Dashboard Pollution: Each token creates an "order" (TKNxxxxxxx) in alwaysdata's PayZen merchant dashboard, polluting order history and potentially triggering fraud alerts.
3. Internal Infrastructure Disclosure: The jSessionId field leaks internal PayZen load-balancer node hostnames (vadapi01-tls-prod-fr-lyra, vadapi02-tls-prod-fr-lyra), which could assist in infrastructure mapping.
Fix 1. Require authentication (valid CSRF token from a logged-in session OR a registration-initiated session) before generating a PayZen token 2. Add server-side rate limiting: maximum 1 token per IP per 60 seconds, or tie token generation to an active registration session 3. Consider using sandbox/test mode for development and only switching to PRODUCTION for verified registration attempts
Note: No actual PayZen sessions were initiated beyond what is recorded in the Reproduce steps above. The DoW impact is based on the observed rate limit absence and standard PayZen merchant billing patterns.
|