Skip to content

Payment Exploit #4

Description

@oleonardosilva

Critical Security Issue: Unverified Payment Webhook Source

Description
Our application currently does not verify if the incoming webhook events truly originate from MercadoPago. This lack of validation leaves us vulnerable to external exploit attempts, as unauthorized actors could potentially send fake notifications to our webhook endpoint.

Risk
If not addressed, this vulnerability could expose the application to fraud, potentially allowing malicious actors to trigger or manipulate payment processing events.

Proposed Solution
To prevent this exploit, we need to validate each incoming webhook notification from MercadoPago by checking the x-signature header, which contains a cryptographic signature ensuring the authenticity of the notification. The header has the format ts=timestamp,v1=signature, where:

  • ts: The timestamp when the message was generated.
  • v1: The HMAC signature generated by MercadoPago.

Validation Steps

  1. Parse the x-signature header and extract ts and v1 components.
  2. Retrieve the secret key provided by MercadoPago from our application's environment variables.
  3. Construct a manifest string with required values (e.g., id, request-id, ts).
  4. Generate an HMAC using SHA-256 with the manifest string and secret key.
  5. Compare the resulting hash with the v1 signature from the header. If they match, the message is authentic.

Here’s an example of how this verification could be implemented in Java, converted from JavaScript:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Map;

public boolean verifyWebhook(Map<String, String> headers, String requestBody, String secret) throws Exception {
    String xSignature = headers.get("x-signature");
    String xRequestId = headers.get("x-request-id");
    
    String[] parts = xSignature.split(",");
    String ts = null;
    String hash = null;
    for (String part : parts) {
        String[] keyValue = part.split("=");
        if ("ts".equals(keyValue[0])) {
            ts = keyValue[1];
        } else if ("v1".equals(keyValue[0])) {
            hash = keyValue[1];
        }
    }

    String manifest = String.format("id:%s;request-id:%s;ts:%s;", extractDataId(requestBody), xRequestId, ts);

    Mac hmac = Mac.getInstance("HmacSHA256");
    SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
    hmac.init(secretKeySpec);
    byte[] signature = hmac.doFinal(manifest.getBytes());

    String computedHash = Base64.getEncoder().encodeToString(signature);
    return computedHash.equals(hash);
}

private String extractDataId(String requestBody) {
    // Implementation to extract data.id from request body JSON
}

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

exploitCritical vulnerability of application

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions