> ## Documentation Index
> Fetch the complete documentation index at: https://docs.injective.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Emergency upgrade to v1.20.4-bl.2

> Upgrade and AppHash recovery instructions for Injective mainnet validators, exchanges, and node operators.

<Warning>
  **Why this emergency upgrade happened**

  BitGet, an exchange unrelated to Injective, reported a compromise and requested assistance recovering its funds, some of which may have interacted with Injective alongside other major chains. This patch introduced an on-chain blocklist to prevent an attacker from moving **BitGet's affected funds**. It was a **one-time emergency intervention to assist BitGet's fund recovery and support the wider ecosystem**. Initial distribution and coordination focused on validators, with public communication limited to avoid alerting the attacker before containment was in place.

  We recognize that exchanges and other node operators did not receive sufficient advance notice or clear instructions that they also needed to upgrade. We apologize for the resulting disruption. This exceptional response does not replace the normal coordinated upgrade process.

  On October 7, a transaction involving a blocked address exposed the difference between patched and unpatched nodes. Unpatched nodes encountered an AppHash mismatch while the network continued producing blocks. **All mainnet nodes must run the patch, including sentries, RPC nodes, and exchange infrastructure.**
</Warning>

## Summary

`v1.20.4-bl.2` is an emergency patch on the `v1.20.4` release line for **Injective mainnet (`injective-1`)**. Its consensus blocklist activated at block **184,950,000**, which has already passed. Upgrade now; there is no scheduled chain halt, governance upgrade handler, or state migration for this patch. Do not wait for a halt or set a new `--halt-height`.

| Node status | Required action |
| - | - |
| Running an unpatched binary and stopped with the October 7 AppHash mismatch | Stop the node, back up its state, roll back one block **using the existing binary**, then install the patch and restart. |
| Running an unpatched binary without the mismatch | Stop the node, back up its state, install the patch, and restart. Skip rollback. |
| Already running `v1.20.4-bl.2` and syncing normally | No rollback or reinstall is needed. Check that every sentry, RPC, and other node you operate is also patched. |

This applies to validators, sentries, full nodes, public and private RPC/broadcast nodes, and nodes serving exchanges, explorers, and other integrations.

## 1. Choose and verify your release

Choose either the binary archive or Docker image. **Docker operators can skip the archive downloads and use the image directly.**

### Option A: binary archive

The [official release manifest](https://storage.googleapis.com/injective-chain-releases/status.json) lists the hosted binaries. Download the archive for your platform:

| Platform | Download |
| - | - |
| Linux AMD64 | [injective-v1.20.4-bl.2-linux-amd64.zip](https://storage.googleapis.com/injective-chain-releases/v1.20.4-bl.2/injective-v1.20.4-bl.2-linux-amd64.zip) |
| macOS Apple Silicon | [injective-v1.20.4-bl.2-darwin-arm64.zip](https://storage.googleapis.com/injective-chain-releases/v1.20.4-bl.2/injective-v1.20.4-bl.2-darwin-arm64.zip) |
| SHA-256 checksums | [SHA256SUMS.zip.txt](https://storage.googleapis.com/injective-chain-releases/v1.20.4-bl.2/SHA256SUMS.zip.txt) |

For Linux AMD64, download into a staging directory without replacing your running binary:

```bash theme={null}
mkdir -p ~/injective-v1.20.4-bl.2
cd ~/injective-v1.20.4-bl.2
curl -fLO https://storage.googleapis.com/injective-chain-releases/v1.20.4-bl.2/injective-v1.20.4-bl.2-linux-amd64.zip
echo '81f49009d1652fe8688bf6662c6d4d42ad65d7039207fd77ec2a161050973df2  injective-v1.20.4-bl.2-linux-amd64.zip' | sha256sum -c -
```

Continue only if the checksum reports `OK`. Then extract the archive:

```bash theme={null}
unzip injective-v1.20.4-bl.2-linux-amd64.zip
```

For macOS, use `shasum -a 256` and compare the archive against the corresponding entry in the checksum file.

### Option B: Docker image

The initial release distributed the patch as the following Docker image:

```text theme={null}
injectivelabs/injective-core:v1.20.4-bl.2
```

Pull the image and verify its binary without mounting your node data:

```bash theme={null}
docker pull injectivelabs/injective-core:v1.20.4-bl.2
docker run --rm injectivelabs/injective-core:v1.20.4-bl.2 injectived version
```

The initial release recorded the following output for AMD64:

```text theme={null}
Version v1.20.4-bl.2 (1ffa252)
Compiled at 20260928-0409 using Go go1.26.8 (amd64)
```

Continue through the stop, backup, recovery, and restart steps below using your existing container deployment. Keep the old image available: affected nodes must complete rollback with that image before switching to the patch. The Docker image includes the runtime libraries, so container operators do not need to install the archive's `libwasmvm` on the host.

## 2. Stop the node and back up its state

Stop the node through your existing service manager or container deployment. Stop its supervisor as well so it cannot automatically restart during recovery. Confirm that no `injectived` process is accessing the node's data directory.

Back up your node configuration, keys, and data before proceeding. Keep the existing binary available until any required rollback is complete. The commands below assume the default home directory, `~/.injectived`; use your configured `--home` path if different.

**Docker Compose example:** Run the commands from your existing Compose project, using the same Compose files and environment as your normal deployment. Set `node_service` to your actual service name and `container_node_home` to its existing home path **inside the container**; the values below are examples. Confirm that this home is backed by your existing bind mount or named volume, then stop the service:

```bash theme={null}
node_service=injectived
container_node_home=/root/.injectived
docker compose stop "$node_service"
```

Back up that mounted node home after shutdown. Keep these variables set for the Compose commands below. If you use plain Docker or another orchestrator, stop the existing node container through that deployment and preserve its mounts and settings.

<Warning>
  **Validators:** After the node has fully stopped, separately back up `~/.injectived/data/priv_validator_state.json` outside the data directory. Preserve this exact signing state through rollback or snapshot recovery and restore it before restarting. For a remote signer, preserve its signing state using your existing signer procedure. Never reset signing state or run two instances with the same validator key.
</Warning>

## 3. Recover an affected node, if needed

Only perform this step if your node encountered the October 7 AppHash mismatch. A reported error was:

```text theme={null}
panic: Precommit step; +2/3 prevoted for an invalid block: wrong Block.Header.AppHash.
```

For archival nodes or nodes with large databases, contact support to confirm a recovery approach before attempting rollback; restoring a suitable snapshot may be preferable.

With the node stopped, **use the same binary version that was running when the mismatch occurred**, before installing the patch:

```bash theme={null}
injectived rollback --hard -n 1 --home ~/.injectived
```

This one-block rollback followed by the binary upgrade was tested during the incident. Use the actual executable from your service configuration, not a different `injectived` on your shell's `PATH`.

* **Cosmovisor:** Run rollback using the existing `$DAEMON_HOME/cosmovisor/current/bin/injectived`, with `--home` pointing to that node's home directory.
* **Containers:** Run the rollback as a one-off command using the **old image**, the same data volume, node home, and user permissions. Keep the normal node container stopped throughout.

For Docker Compose, leave the service's `image` set to the exact old image used by the affected node until rollback succeeds. Run this **instead of** the host rollback command above, after completing the backup:

```bash theme={null}
docker compose run --rm --no-deps --pull never --entrypoint injectived \
  "$node_service" rollback --hard -n 1 --home "$container_node_home"
```

This reuses the service's configured mounts, environment, and user. The example assumes `injectived` is available directly in the image; preserve any required initialization if your deployment uses a custom wrapper.

Wait for rollback to finish successfully before replacing the binary. The incident recovery instructions estimate roughly 10 seconds to one minute; large or archival databases can take substantially longer. Do not repeatedly roll back additional blocks if the command fails or the mismatch persists. Keep the node stopped and contact support with its version, height, and logs.

If rollback is unavailable or fails, obtain a suitable snapshot through the [Chain Portal](https://chain.injective.network/snapshots) or your Injective support contact. A snapshot from before block **186,223,485** can be replayed with the patched binary. Preserve your validator signing state and follow the [snapshot recovery procedure](/infra/coordinated-upgrades#recovering-from-a-snapshot).

## 4. Install the patch

Once any required rollback has completed:

* **Binary deployments:** Replace the `injectived` executable used by your service with the one from the verified archive. Install the bundled `libwasmvm` library in the library location used by your deployment, and preserve the service's ownership and permissions.
* **Cosmovisor:** Replace `injectived` in `$DAEMON_HOME/cosmovisor/current/bin` and place the bundled library where your service loads it. There is no upgrade handler for this patch, so placing it in a new `upgrades` directory will not activate it automatically.
* **Containers:** Update the existing deployment to `injectivelabs/injective-core:v1.20.4-bl.2`, retaining its data volume, configuration, user, and startup flags.

For Docker Compose, change only the node service's `image` value (or the environment variable supplying it) to `injectivelabs/injective-core:v1.20.4-bl.2`. Pull and verify the configured image while the node remains stopped:

```bash theme={null}
docker compose pull "$node_service"
docker compose run --rm --no-deps --entrypoint injectived "$node_service" version
```

Before starting, run `version` against the exact executable or image your service will use and confirm:

```text theme={null}
Version v1.20.4-bl.2 (1ffa252)
```

### Optional: local mempool blocklist

The consensus blocklist is built into the patched binary and requires no configuration. The following `app.toml` entry adds local transaction-admission filtering and is **optional**; it is not a substitute for upgrading the binary.

If you enable it, add this entry at the **top level** of `~/.injectived/config/app.toml`, before any TOML section headers such as `[api]`:

```toml theme={null}
mempool-blocked-signers = ["inj134wrp6mctpq4czhw6rghekt3js3ac7c4s8ya3d"]
```

If the key already exists, update it without duplicating the key or removing any other configured addresses. Invalid addresses prevent the node from starting.

## 5. Restart and verify

Validators must restore and verify the signing-state backup taken after stopping the node before restarting. Start the node through your existing service manager or container deployment.

For Docker Compose, recreate the service with the new image, then verify the binary inside the running container and inspect its logs:

```bash theme={null}
docker compose up -d --no-deps "$node_service"
docker compose exec "$node_service" injectived version
docker compose logs --tail 100 "$node_service"
```

Use `up` to apply the image change; restarting the old container alone does not replace its image. For plain Docker or another orchestrator, recreate the stopped node container from the patched image using its existing mounts, ports, environment, user, and startup arguments. Keep only one instance using the node's data and validator key.

Check your logs for successful startup and confirm that the AppHash mismatch no longer appears. Query your node's local RPC endpoint (adjust the address if needed):

```bash theme={null}
curl -fsS http://localhost:26657/status \
  | jq '.result | {network: .node_info.network, latest_block_height: .sync_info.latest_block_height, catching_up: .sync_info.catching_up}'
```

Confirm that:

* The network is `injective-1`.
* The block height advances across successive checks and catches up to the network.
* `catching_up` becomes `false` once synchronization completes.
* Validators resume signing, and exchange/RPC operators verify their downstream services receive current blocks.

Repeat the upgrade for every node you operate, including sentries and RPC nodes that do not participate in validation.

## Support

If recovery fails, keep the node stopped and share the binary version, last processed height, database backend, and relevant error logs with your existing Injective coordination contact or the team on [Discord](https://discord.gg/injective). Do not share private keys or signer credentials.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.