3DS Disabled in Payment SDK Configuration
3D Secure is the primary mechanism for Strong Customer Authentication under PSD2. A cardholder initiates a payment, the card network triggers a challenge, the issuing bank authenticates the user with a second factor, and only then does the authorization proceed. When the merchant disables 3DS in the SDK configuration, none of that happens. The charge is submitted directly to the acquirer with no SCA challenge, no second factor, and no issuer verification. On the application assessed here, 3DS was disabled in both the client-side SDK bundle and confirmed off in the live API response.
3DS disabled — two confirmations
The first confirmation came from the JavaScript bundle. The payment SDK was initialised
with a client-side configuration object that included "threeDSecureEnabled": false.
The second confirmation came from the API itself — the payment endpoint returned the same
flag with no 3DS challenge objects:
# client-side SDK initialisation (extracted from JS bundle — lab)
paymentSDK.init({
publishableKey: "<publishable-key>",
environment: "production",
threeDSecureEnabled: false,
challengeMode: "NO_PREFERENCE"
});
# live API payment response (authenticated request — lab)
POST /api/v2/payments
{
"id": "pay_lab_example_001",
"amount": "<amount>",
"currency": "eur",
"status": "pending",
"threeDSecureEnabled": false,
"sca_enforcement": "off",
"challenges": []
}
# both client config and API response confirm 3DS disabled
# "challenges": [] — no SCA challenge triggered for any transaction
The publishable key in the bundle is meant to be client-side — that is by design, and exposing it is not the finding. The finding is what it reveals: with the key, any visitor can read the payment SDK configuration straight from browser devtools and confirm that 3DS is switched off. The sensitive thing on display is not the key. It is the security posture of every transaction the platform processes.
Why a client-side flag is not the whole story
A disabled flag in a JavaScript bundle could, in isolation, be an incomplete picture —
the frontend might request no challenge while the server still enforces one. That is why
the API confirmation matters. The live payment response returned "sca_enforcement": "off"
and an empty challenges array, proving the absence of SCA was server-side, not
a cosmetic client setting. A control that is off in the config and off in the
response is a control that does not exist.
The test timeline
JavaScript bundle reviewed for payment SDK configuration. threeDSecureEnabled: false found in the SDK init object. challengeMode: "NO_PREFERENCE" — 3DS will not be requested for any transaction.
Live API confirms 3DS disabled. Payment endpoint returns "threeDSecureEnabled": false and "challenges": []. Server-side enforcement absent — not just a UI configuration.
SCA bypass confirmed across the payment flow. With no challenge triggered, every transaction submits straight to the acquirer with no second factor. PSD2 non-compliance for EU cardholders established.
Finding documented. 3DS configuration exposed client-side and confirmed off in the live response; remediation path confirmed with the SDK documentation.
Fixing the payment security model
- Enable 3DS in the SDK configuration and at the processor level. Set
threeDSecureEnabled: trueandchallengeMode: "CHALLENGE_REQUESTED"in the SDK. Verify with the payment processor that SCA enforcement is active server-side — a client-side flag alone is not sufficient. For EU cardholders, 3DS2 is required for PSD2 compliance. - Enforce SCA server-side, not just in the SDK. The authoritative check must live at the payment API and the processor. The client flag is a hint to the UI; the server must reject any authorization that should have carried an SCA challenge and did not.
- Keep secret credentials out of the bundle. Publishable keys are expected on the client; secret keys must never be shipped in JavaScript sent to the browser. Review the bundle for any secret-prefixed keys and rotate any that are found — a secret key in client code is a separate, higher-severity finding.
- Treat fraud rules as the last line, not the first. On a platform where SCA is the primary control, fraud rules must block rather than alert. If the risk engine only flags suspicious transactions, that configuration must be reviewed and moved to blocking.
The takeaway
3DS disabled is not a subtle misconfiguration — it is a single boolean that removes the primary EU payment authentication requirement. It was present in the JS bundle, in the API response, and readable by any user who opened devtools. The fix is the same place it was turned off.