Jul 28, 2026·6 min read·34 visits
Unauthenticated remote attackers can bypass webhook authorization and spoof transaction events by exploiting a fail-open design when custom registration paths are configured in the pytonapi dispatcher.
An authentication bypass vulnerability exists in the pytonapi library when custom paths are registered in the TonapiWebhookDispatcher. The application fails to retrieve or store secure tokens for custom paths, leading to a fail-open authorization check that allows unauthenticated remote attackers to send spoofed webhook events directly to internal handlers.
The pytonapi library provides a Python Software Development Kit (SDK) for TONAPI, enabling developer integration with The Open Network (TON) blockchain. The SDK includes a webhook dispatcher class, TonapiWebhookDispatcher, designed to receive and verify asynchronous event notifications such as ledger transactions and smart contract deployments. To ensure request integrity, the dispatcher relies on authentication tokens supplied via the HTTP Authorization header of incoming POST requests.
When developers implement the default webhook routing configuration, the library registers and verifies paths correctly. However, the dispatcher allows developers to register custom endpoint paths using the path keyword parameter on handlers. If a custom path is specified, the internal initialization routine neglects to populate the corresponding verification tokens for that specific route.
This omission results in a logical disconnect within the routing and verification pipeline. Incoming requests directed to custom paths bypass the authentication guard entirely because of a fail-open execution design. An unauthenticated remote attacker can exploit this condition to inject forged transaction payloads directly into user-defined event handlers.
The flaw resides in the initialization sequence within pytonapi/webhook/dispatcher.py. During the invocation of the setup() method, the dispatcher iterates over registered event types to register hook endpoints with the upstream TONAPI client. In versions prior to 2.2.1, the method retrieves tokens solely for the hardcoded suffixes defined in self.DEFAULT_SUFFIXES.
These default suffixes correspond to standard endpoints like /hook/account-tx. If a handler is registered with a custom path (such as /hook/custom), the dispatcher records the custom path for routing but fails to request or associate a secure authorization token with this path inside the self._tokens dictionary. As a consequence, the token lookup table lacks keys representing custom-registered paths.
When the dispatcher receives an HTTP POST request, the process() method retrieves the target route and performs a lookup: expected_token = self._tokens.get(path). For custom paths, this lookup returns None. The validation logic is structured as a conditional check: if expected_token is not None and authorization != f"Bearer {expected_token}": raise TONAPIError(...). Because the expected token is None, the entire conditional block is evaluated as False, bypassing the validation check and executing the handler.
The vulnerable implementation of the dispatcher setup sequence relies on default suffixes to create webhook tokens:
# Vulnerable initialization block in pytonapi <= 2.2.0
suffix = self.DEFAULT_SUFFIXES[event_type]
local_path = self._path + suffix
webhook = await self._client.ensure(f"{self._url}{suffix}")
self._tokens[local_path] = webhook.token # Token populated only for default suffixThe matching authentication logic inside process() relies on a fail-open validation approach:
# Fail-open checking logic in process()
expected_token = self._tokens.get(path) # Resolves to None for custom paths
if expected_token is not None and authorization != f"Bearer {expected_token}":
raise TONAPIError("Invalid webhook token") # Skipped entirelyThe remediation applied in version 2.2.1 modifies the setup loop to iterate over all distinct paths defined across all handlers:
# Remedied initialization loop in pytonapi 2.2.1
for local_path in sorted({path for _, _, path in handlers}):
webhook = await self._client.ensure(self._endpoint_for_path(local_path))
self._tokens[local_path] = webhook.token # Token is correctly generated and mappedThis structural shift ensures that every custom route receives a dedicated token. The reverse path mapper was also refactored to handle multiple paths reliably.
To exploit this vulnerability, an attacker must first locate an application running a vulnerable version of pytonapi that registers custom paths for incoming webhook payloads. Because the custom endpoint must be publicly accessible to receive updates from the TONAPI services, the endpoint is exposed directly to the internet.
No specialized exploitation tools are required to trigger the vulnerability. The attacker can structure an HTTP POST request targeting the custom URL path. The request body must contain a structured JSON payload mimicking a legitimate blockchain event, such as a transaction receipt.
Because of the lack of token validation, the attacker does not need to supply a valid Authorization header. Sending the request with no authorization header, or with a randomized dummy string, succeeds. The server processes the fake transaction payload as legitimate, triggering the application's processing routines which can lead to spoofed ledger deposits.
Below is a schematic mapping of the vulnerability logical flow:
The vulnerability allows complete bypass of authentication controls, leading to a High integrity impact. An attacker cannot read sensitive configuration values directly through this endpoint, keeping confidentiality impact low or none. However, the integrity of application-level transactions is completely compromised.
In applications handling financial actions or cryptocurrency exchanges, webhook dispatchers are utilized to verify user deposits and payments. Spoofing these webhooks allows attackers to claim credit for arbitrary transactions without actually depositing funds onto the blockchain. This can lead to severe financial discrepancies.
This logical flaw is classified under CWE-287 (Improper Authentication) and maps to MITRE ATT&CK technique T1190 (Exploit Public-Facing Application). Because it requires zero interaction from users and can be performed with low complexity over standard HTTP, the CVSS v3.1 score is calculated as 7.5 (High).
The definitive resolution for this issue is to upgrade the pytonapi installation to version 2.2.1 or later. This version ensures proper token generation and enforcement for all custom paths. The package can be upgraded from PyPI using standard package management utilities.
If updating the dependency is not immediately possible, developers must mitigate the risk by eliminating the use of custom paths. Removing the path argument from webhook decorator registrations forces the library to fall back onto its default suffixes, which are correctly authenticated even in vulnerable library versions.
Additionally, network-level ingress filtering can be implemented to restrict incoming requests to the webhook endpoints. Standard TONAPI webhook requests originate from known, documented server IP ranges, allowing developers to construct firewall or reverse proxy rules to drop requests originating from unauthorized addresses.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
pytonapi nessshon | >= 2.0.0, < 2.2.1 | 2.2.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-287 (Improper Authentication) |
| Attack Vector | Network |
| CVSS v3.1 Score | 7.5 (High) |
| Impact | High Integrity Compromise |
| Exploit Status | PoC Available |
| KEV Status | Not Listed |
The software does not prove, or insufficiently proves, the identity of an actor before granting access to resources.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.