monero.loveA little love for the network.
← All news

Haveno / Security / Development

Haveno Developers Propose Security Improvements for P2P Messages, Wallet Credentials, and API Access

Haveno security PR 2856 proposes mailbox, wallet credential and API changes. See what the code and tests establish, plus review and release limits.

Peer messages pass through a mechanical sorting gate beside a computer, wallet and key on textured cream paper.

Haveno developer woodser has proposed changes to stop failed mailbox messages suppressing valid ones and to remove notification secrets from logs. The work also adds password confirmation before displaying private wallet data. Pull request #2856 also tightens API request handling, limits new persistent P2P data and checks more of the software used to build releases.

The proposal is real and belongs to the upstream haveno-dex/haveno repository. Its public page, GitHub API record and recent pull-request listing all identify the same 12-commit branch. The PR remained open and unmerged at the November 10, 2026, 16:47 UTC status check. The inspected head is fd120f7. There were no submitted reviews or discussion comments. Current PR record.

These corrections remain proposals. The public material reviewed here contains regression tests and specific code changes, but no report of a successful attack on a trading network. Claims of stolen funds or broken Monero cryptography would go beyond that evidence.

What is under review

Haveno supplies software for independently operated trading networks. The desktop application manages a local wallet and exchanges messages with peers. A separate daemon API lets authorized clients make requests to the application. Those interfaces have different security requirements, and a weakness in one does not imply unrestricted access through another. Our Haveno and RetoSwap guide explains the distinction between upstream software and the network distributing your application.

Area What the proposal changes Relevant boundary
Mailbox cache Identifies failed entries by payload hash instead of sender-chosen ID Untrusted messages versus local retry decisions
Mobile notifications Removes plaintext, encryption keys and delivery-token logging Application secrets versus retained logs
Private wallet data Requests password confirmation for encrypted wallets An open application versus sensitive display
API calls Stops rejected calls reaching handlers and enforces configured account-password requirements Authenticated requests versus permitted work
P2P storage and sending Limits admission of new persistent payloads and splits oversized bundles Peer traffic versus memory, storage and frame limits
Builds Pins selected Actions and verifies Gradle and WiX downloads External build inputs versus release artifacts

This is separate from the installer-signature and Java-monitoring review. That article covers PR #2841 and PR #2842. Both were also still open and unmerged at this check. PR #2856 concerns application messaging, credentials, resource handling and release tooling.

Mailbox messages: the wrong identity for an ignore list

A mailbox lets a peer leave an encrypted message for a recipient who is not immediately reachable. Haveno remembers entries it could not decrypt, avoiding repeated work when it sees them again. The existing code keys that ignore list by a message's UID, an identifier supplied with the message.

A UID can appear on different payloads. If the first fails to decrypt and its UID enters the ignore list, the recipient can skip a valid message with that UID before attempting decryption. The collision involves an application identifier. The cryptographic hashes can remain different.

The proposal instead computes a 32-byte hash of the mailbox storage payload and uses that as the cache key. Different payloads then receive different cache entries. It also uses a new persisted cache name, IgnoredMailboxMapByHash, so an upgrade cannot mistake old sender-controlled identifiers for trusted hash entries. Mailbox correction.

The old cache can suppress a valid payload after a different payload with the same UID fails. The proposed cache uses payload hashes to keep their checks separate.

The added test supplies a valid encrypted message and a modified payload sharing its UID. It checks that the recipient recognizes the valid message after processing the invalid entry. A second test checks separation of the old and new persisted caches. The tests mock the entries in mailbox storage and call the decryption method directly. Regression-test source.

For a network attack, the conflicting entry must pass the surrounding storage checks and reach decryption before the valid entry. We have not reproduced that full path. The storage-entry code also checks signatures and key relationships. The test stops short of those checks and tests suppression rather than access to another user's conversation. It supports the narrower concern that the cache can suppress an otherwise valid message.

Notification secrets do not belong in logs

The mobile-notification code contains informational log statements for message text, serialized notification content, an encryption key, an initialization vector, ciphertext and a delivery token. Another statement logs a truncated prefix of the phone-pairing value. The proposal removes those statements. Notification logging diff.

A person or service with access to the resulting logs could read information intended to remain within the notification feature. Plaintext in a log is already readable without decrypting a notification. The encryption key in this path belongs to the mobile-notification feature. The wallet's Monero private spend key serves a separate purpose.

Exposure depends on use of the feature, the logging configuration and who can read or receive those logs. The source directly shows the sensitive log statements, although the reviewed records do not report anyone collecting users' notification data. Existing logs, support attachments and backups remain outside this patch.

Password confirmation and three different credentials

The wallet-data window currently updates its output when the user selects the option to include private keys. The patch adds a password prompt when the wallet is encrypted. A successful check permits the sensitive display, while closing the prompt resets the selection. The wallet-information button and keyboard shortcut both open the revised window. Private-data display change.

This protects a specific action in an already accessible application. Someone able to operate an unattended session should not automatically get permission to display its private data. It does not protect against malware controlling the process or operating system, and it cannot ask for a password on a wallet that has none. We inspected the code without reproducing the desktop interaction.

The affected paths use different credentials:

  • The account or wallet password protects the user's local account and wallet.
  • The Haveno API password authorizes clients calling Haveno's daemon API.
  • A Monero daemon login authenticates a wallet's connection to a node that requires credentials.

For the last of these, the patch moves a compatible daemon login out of the wallet-RPC process arguments and into its existing restricted temporary configuration file. This reduces exposure through process-command inspection. The application already uses that file for its separate wallet-RPC login. Credential-file change.

The change has an explicit exception. Credentials containing a comment marker, a line break or leading or trailing whitespace remain in the arguments because moving them into the configuration file could change their interpretation. Some daemon passwords can still remain in command lines. A protected file also does not protect a secret from the account running the application or from a sufficiently privileged attacker.

API hardening is not a new authentication system

Haveno's inspected code already checks an API password and refuses to start the gRPC server with an empty one. Its listener defaults to loopback. Loopback restricts the listener to the local machine unless the operator changes its exposure. PR #2856 does not introduce those protections. Server initialization and configuration defaults.

The patch corrects how the API enforces rate limits. The old interceptor closes a call that exceeds its limit but still invokes the next handler. The proposal returns a listener that ignores the rejected request instead. Its regression test checks that a rejected call leaves the handler untouched, even if a message arrives after closure. The test exercises rate limiting after a call reaches that interceptor. Authentication bypass is outside the behavior it tests. Rate-limit correction and test.

Another correction enforces passwordRequired inside account creation. If an operator enables that option, the service rejects an empty or missing account password before creating a wallet or keys. The default for this option is false, and the patch does not change it. The change enforces an operator's account-password policy. API authentication remains a separate check. Account-creation change and test.

The command-line client also gains an API-password environment variable and an interactive prompt as alternatives to a command-line argument. Arguments keep precedence, followed by HAVENO_API_PASSWORD, then the prompt when a console is available. Environment variables reduce one exposure route but are not a secret vault. Their accessibility depends on the host, account privileges and process environment. CLI credential handling.

The patch also removes cancelled notification streams from the registered listener collection. Retaining abandoned listeners can consume resources even though those clients no longer need updates. Exploitation would require reaching the relevant API path and creating enough abandoned state. The change is not evidence that someone has done so. Notification-listener cleanup.

Limiting persistent data and oversized bundles

Some P2P payloads enter append-only storage. Those records accumulate, so even small messages can eventually consume considerable storage.

The proposal adds an admission limiter for new payloads received through the broadcast path. Its settings allow a burst of 500 and a sustained rate of five admissions per second. It checks duplicates and basic payload conditions first. The storage service shares one limiter across peers. Local additions and synchronization paths that do not request this check remain outside it. Persistent-payload limiter.

The rate control leaves total disk usage uncapped, so resource exhaustion remains possible. A peer must supply payloads that reach and pass the preceding checks. A shared admission budget can also reject legitimate new entries during a flood. The regression test covers new-versus-duplicate admission, local additions and counter saturation. Measurements of live-network storage exhaustion and availability under attack remain unavailable.

A separate change handles outgoing bundles. Haveno already limits individual messages to 10 MiB. The new send-path check recursively splits a bundle that exceeds this limit. The sender rejects an individual envelope that is still too large before writing it. Tests check that split bundles preserve their entries and that rejection does not close the connection. Outgoing bundle handling and tests.

This makes outgoing work respect an existing size boundary. Inbound limits predate the patch, and the limit on individual frames leaves total memory use as a separate concern.

Checking the tools used to make releases

The build changes add the expected Gradle distribution checksum, verify the SHA-256 digest of the downloaded WiX installer before execution, and replace version tags with commit hashes for three third-party GitHub Actions. The workflow also declares token permissions. The release-building job retains write access to repository contents because it publishes installers. Gradle checksum and Actions and WiX changes.

Pinning makes the selected code explicit. A checksum can reject a download that differs from the expected bytes. Neither establishes that the selected dependency is safe, and this diff is not a new verification system for every Java dependency. The provenance of the newly pinned checksum values was not independently validated in this review.

Release status and what users can check

The latest upstream stable release returned by GitHub was v1.12.0, published October 29. Its mailbox, notification, wallet-display, API-rate-limit and persistent-payload files still contain the pre-patch implementations. No inspected stable release includes these proposed corrections.

That comparison identifies old behavior in one release. It does not establish the first affected version, a complete vulnerable-version range, or the state of independently packaged Haveno networks. Users should check their network publisher's release information before assuming an upstream change is present in their installed application.

GitHub reported seven successful checks for the inspected head, including five platform builds and two analysis checks. The build steps ran Gradle tests, but the ARM Linux workflow explicitly skipped desktop tests. No reviewer had submitted an approval or requested changes. CI results report the automated jobs' outcomes. They leave security review and independent attack reproduction as separate work. Head check runs and build job steps.

Users and operators can check who has access to their unlocked application and its logs or backups. Operators running an API should review its exposure and credentials. Each network's publisher remains the source for its supported updates. Do not attach unreviewed logs or recovery information to a public issue. The Whonix wallet-update guide explains why an operating-system update does not necessarily update a separately installed wallet.

The public PR and repository advisory listing did not establish a CVE, confirmed exploitation, or an affected trading-network incident. The regression tests support narrower statements about code behavior. End-to-end mailbox delivery under adversarial conditions, interactive wallet-display behavior and the practical impact of resource exhaustion remain unverified in this investigation. Review, merge and release status need another check before publication.

Support Monero Love

Help keep the public nodes and packages running. Send any amount of XMR.

Scan with a Monero wallet to donate to Monero Love.89hGTKxRVA3AUeKAbCRBt5TMSzq3MQZooNNsezCpNFjp2oeJPRx8AJeGKA8ziHZNqab78f4Vr1ntxhPDxX5298nnGZjHkhm