v1.0.10 sécu item 7. The SSRF audit flagged callbacks on Hyperswitch +
distribution submissions ; investigating those revealed a different
risk class on the user-supplied return_url fields :
* sell_handler.ConnectOnboard accepts return_url + refresh_url and
forwards them to Stripe Connect.
* kyc_handler.StartVerification accepts return_url and forwards it
to Stripe Identity.
Stripe doesn't fetch these URLs server-side (so SSRF is not the
risk), but it redirects the user's browser there after the flow
completes. Without an allow-list, an attacker can craft an onboarding
or verification link with `return_url=https://attacker.com/phishing`
and a victim who clicks the resulting Stripe URL lands on the
attacker's page after Stripe finishes — open-redirect attack
disguised as a legitimate Stripe flow.
Hyperswitch + distribution were already protected :
* Webhook URLs go through validators.ValidateWebhookURL
(services/webhook_service.go:54) which blocks private IPs +
requires HTTPS — pre-existing SSRF guard from SEC-07.
* Hyperswitch's own callback URL is configured server-side, not
user-supplied (cf. hyperswitch/client.go) — no SSRF surface.
* Distribution submissions don't carry user-supplied callbacks —
the destination platforms are hard-coded.
What's added :
validators/url_validator.go
* ValidateRedirectURL(rawURL, allowedHosts) — accepts http or
https (since Stripe-redirect targets may be local dev hosts),
requires hostname to match one of allowedHosts exactly OR be
a subdomain of one. Empty allowedHosts ⇒ permissive (used in
dev / unconfigured envs ; only checks for non-internal IPs).
* Reuses the existing IsInternalOrPrivateURL guard so SSRF
protection still applies for the permissive branch.
handlers/sell_handler.go + handlers/kyc_handler.go
* Both handlers now take an allowedRedirectHosts []string param
at construction. Validation runs after the URL defaults are
applied so the caller's submitted URL is checked, not the
backend-derived fallback.
* Validation failure → 400 with a clear message ("invalid
return_url: <reason>") so the SPA can render the right error.
api/routes_marketplace.go
* Both handlers receive the existing
cfg.OAuthAllowedRedirectDomains list at construction. Same
list as the OAuth callback validation, same operator config,
single source of truth.
Tests pass : go test ./internal/{handlers,validators} -short.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SEC-07: Strengthened ValidateWebhookURL to require HTTPS only (was
allowing HTTP). Private IP ranges, localhost, and cloud metadata
endpoints remain blocked.
- Conflit SQLx résolu (alignement sur version 0.7)
- build.rs configurés pour protoc dans chat/stream servers
- API Prometheus migrée vers HistogramOpts
- Traits Display/Debug corrigés (String au lieu de &dyn Display)
- API TOTP corrigée (totp-rs 5.4 avec Secret::Encoded)
- Layers tracing-subscriber corrigés (types conditionnels)
- VezaError/VezaResult exportés dans lib.rs
- TransactionProvider simplifié (retour void au lieu de Box<dyn>)
- VezaConfig contraint Serialize pour to_json()
Files: veza-common/Cargo.toml, veza-common/src/*.rs, veza-chat-server/Cargo.toml, veza-chat-server/build.rs, veza-stream-server/Cargo.toml, veza-stream-server/build.rs, VEZA_ROADMAP.json
Hours: 8 estimated, 3 actual
- Enhanced PasswordValidator with additional security checks:
* Maximum length validation (128 characters)
* Common password detection (password, 123456, qwerty, etc.)
* Repetitive pattern detection (aaaa, 1111, etc.)
* Sequential pattern detection (1234, abcd, qwerty, etc.)
- Added ValidatePasswordChange method to ensure new password is
sufficiently different from old password (similarity check)
- Updated PasswordService to use enhanced validator consistently
- Replaced utils.ValidatePasswordStrength with validators.PasswordValidator
- All password operations now use the same comprehensive validation rules
Phase: PHASE-4
Priority: P1
Progress: 8/267 (3.0%)