setup-monero-wallet.sh: monero-wallet-cli is downloaded and root-installed without signature or checksum verification #3

Open
opened 2026-09-01 07:28:02 +00:00 by SoulReaver · 1 comment

Same caveat as my other issue: I am not an expert here.

In monero-wallet-rpc/setup-monero-wallet.sh, install_monero_wallet_cli_if_missing downloads the CLI archive and installs it as root:

curl -fsSL "$archive_url" | tar -xj -C "$tmp_dir"
extracted_cli="$(find "$tmp_dir" -type f -name monero-wallet-cli | head -n 1)"
...
run_privileged install -m 755 "$extracted_cli" "$MONERO_CLI_INSTALL_PATH"

I do not see a signature check against the signed hashes file that getmonero.org publishes, or a SHA256 comparison against a pinned value. The binary that comes out of this is what then generates the shop wallet, so whatever it produces is what receives the shop's money.

The reason this stood out to me is the November 2019 incident where getmonero.org served a malicious CLI binary for a short window and people lost funds. Verifying the download is the standard advice that came out of that, and this script both skips it and runs the result as root during wallet creation.

What I would expect is fetching the hashes file alongside the archive and verifying it against the Monero maintainer signing key before installing, or at minimum comparing a SHA256 pinned next to MONERO_VERSION in the env file.

Two smaller things in the same script while I am here.

The wallet password is passed as a command line argument:

monero-wallet-cli "--${NETWORK}" \
    --offline \
    ...
    --password "$MONERO_WALLET_PASSWORD" \

That puts it in argv, so it is readable from ps or /proc/<pid>/cmdline by any other local user for as long as the command runs. monero-wallet-cli accepts --password-file instead.

And the wallet is created with --command save, so the mnemonic seed is never displayed. The closing message prints the wallet directory and nothing else. An operator who follows the deployment guide ends up with a live shop wallet and no seed backup, with nothing prompting them to make one. It is recoverable from the keys file, but given who is likely to be deploying this, it seemed like a gap worth closing.

One unrelated note since it is in the same file: the script accepts testnet as a valid MONERO_NETWORK, but NETWORK_ADDRESS_PATTERNS in src/validation/decorators/isMoneroStandardAddress.ts only defines mainnet and stagenet. Happy to open that separately if you would rather track it on its own.

Same caveat as my other issue: I am not an expert here. In `monero-wallet-rpc/setup-monero-wallet.sh`, `install_monero_wallet_cli_if_missing` downloads the CLI archive and installs it as root: ```bash curl -fsSL "$archive_url" | tar -xj -C "$tmp_dir" extracted_cli="$(find "$tmp_dir" -type f -name monero-wallet-cli | head -n 1)" ... run_privileged install -m 755 "$extracted_cli" "$MONERO_CLI_INSTALL_PATH" ``` I do not see a signature check against the signed hashes file that getmonero.org publishes, or a SHA256 comparison against a pinned value. The binary that comes out of this is what then generates the shop wallet, so whatever it produces is what receives the shop's money. The reason this stood out to me is the November 2019 incident where getmonero.org served a malicious CLI binary for a short window and people lost funds. Verifying the download is the standard advice that came out of that, and this script both skips it and runs the result as root during wallet creation. What I would expect is fetching the hashes file alongside the archive and verifying it against the Monero maintainer signing key before installing, or at minimum comparing a SHA256 pinned next to `MONERO_VERSION` in the env file. Two smaller things in the same script while I am here. The wallet password is passed as a command line argument: ```bash monero-wallet-cli "--${NETWORK}" \ --offline \ ... --password "$MONERO_WALLET_PASSWORD" \ ``` That puts it in argv, so it is readable from `ps` or `/proc/<pid>/cmdline` by any other local user for as long as the command runs. `monero-wallet-cli` accepts `--password-file` instead. And the wallet is created with `--command save`, so the mnemonic seed is never displayed. The closing message prints the wallet directory and nothing else. An operator who follows the deployment guide ends up with a live shop wallet and no seed backup, with nothing prompting them to make one. It is recoverable from the keys file, but given who is likely to be deploying this, it seemed like a gap worth closing. One unrelated note since it is in the same file: the script accepts `testnet` as a valid `MONERO_NETWORK`, but `NETWORK_ADDRESS_PATTERNS` in `src/validation/decorators/isMoneroStandardAddress.ts` only defines mainnet and stagenet. Happy to open that separately if you would rather track it on its own.
Owner

Signature check would be nice security in depth addition, but I see it as very low risk now. And at that moment there are more important things to do- bitcoin integration + advertising. I placed that into backlog.

Re this readable password. If someone has access to machine he could read secrets anyway from docker environment. It's more server security concern. Secrets can be also read directly from RAM if someone has physical access to machine, because program at some point must load them into RAM. So it is concern of having trusted VPS provider or using own hardware and having it properly fortified.

Mnemonic can be revealed from CMS -> Wallet -> reveal seed.

The testnet case I treat for now as misconfiguration issue. Deployment guide states to set this value to 'mainnet'

Signature check would be nice security in depth addition, but I see it as very low risk now. And at that moment there are more important things to do- bitcoin integration + advertising. I placed that into backlog. Re this readable password. If someone has access to machine he could read secrets anyway from docker environment. It's more server security concern. Secrets can be also read directly from RAM if someone has physical access to machine, because program at some point must load them into RAM. So it is concern of having trusted VPS provider or using own hardware and having it properly fortified. Mnemonic can be revealed from CMS -> Wallet -> reveal seed. The testnet case I treat for now as misconfiguration issue. Deployment guide states to set this value to 'mainnet'
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nobswebdev/nullcart#3