---
title: Verifying Programs
description:
  Verified builds is a way to link your program to its source code and let
  everyone independently verify that the program was indeed built from that
  provided source code.
---

This guide is meant to be a reference for developers who want to implement
verified builds for their programs on Solana. We will cover what verified builds
are, how to use them, special considerations, and best practices to ensure the
authenticity of your program onchain.

# What are verified builds?

Verified builds ensure that the executable program you deploy to Solana’s
network matches the source code in your repository. By doing this, developers
and users can have confidence that the program running onchain corresponds
exactly to the public codebase, promoting transparency and security.

The verification process involves comparing the hash of the onchain program with
the hash of the locally built program from the source code. This ensures no
discrepancies between the two versions.

> While a verified build should not be considered more secure than an unverified
> build, the build enables developers to self verify the source code matches
> what is deployed onchain. Using the source code, a developer can then validate
> what the code executes when sending a transaction.

The verified builds pipeline was thought out and is maintained by
[Ellipsis Labs](https://ellipsislabs.xyz/) and [OtterSec](https://osec.io/). For
more details, follow the guide in the
[original verified builds](https://github.com/Ellipsis-Labs/solana-verifiable-build)
repository as well and the verify build process directly into the
[Anza](https://www.anza.xyz/) tool suite, once supported there.

# How does it work?

The verification process is done by comparing the hash of the onchain program
with the hash of the locally built program from the source code. You build your
program in a controlled environment using the Solana Verify CLI and Docker. This
ensures that the build process is deterministic and consistent across different
systems. Once you have the executable, you can deploy it to the Solana network.
During the build process a
[PDA](https://explorer.solana.com/address/63XDCHrwZu3mXsw2RUFb4tbNpChuUHx4eA5aJMnHkpQQ/anchor-account)
of the [verify program](https://github.com/otter-sec/otter-verify) will be
created. This PDA contains all the data necessary to verify the program. The PDA
contains the program address, git url, commit hash and the arguments used to
build the program.

Using the data in the PDA everyone can run the verify program command locally
and check if the program was built from the provided source code. Then everyone
can verify for themselves completely trustlessly or can run their own
[verify API](https://github.com/otter-sec/solana-verified-programs-api)
maintained by [OtterSec](https://github.com/otter-sec) to provide an easy access
point for users to check the verification. You can already see these
[API calls](https://verify.osec.io/status/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY)
being used in the
[Solana Explorer](https://explorer.solana.com/address/E1fcPKuV1UJEsTJPpab2Jr8y87ZN73i4CHTPLbWQE6CA/verified-build)
and
[SolanaFM](https://solana.fm/address/E1fcPKuV1UJEsTJPpab2Jr8y87ZN73i4CHTPLbWQE6CA/transactions?cluster=mainnet-alpha),
among other places.

# Why should I use verified builds?

Using verified builds provides the following benefits:

- Security: Guarantee that the program running onchain matches the source code,
  preventing malicious alterations.

- Transparency: Allows other users and developers to validate that the onchain
  program is trustworthy by comparing it with the public codebase.

- Trust: Increase user confidence, as verified builds demonstrate that your
  program's onchain behavior is aligned with your public code. When building
  verifiable programs, you minimize risks associated with running unauthorized
  or malicious code. It also ensures you comply with best practices and give
  security researchers an easy way to contact you. Also wallets and other tools
  can allow transactions from your program more easily as long as it is
  verified.

- Discoverability: When you provide a verified build of you program everyone can
  find your source code, docs, program SDK or IDL and they can also easily
  contact you via github in case there is an issue.

# How do I create verified builds?

To create verified builds, you'll need to follow these steps:

Summary:

- Commit your code to a public repository
- Build a verified build in docker
- Deploy the verified build
- Verify the deployed program against public API

If you verify your program which is not build in a docker container it will most
likely fail because Solana program builds are not deterministic across different
systems.

<Steps>
<Step>

### Install Docker and Cargo

Install the necessary tools ensure you have Docker and Cargo installed. Docker
provides a controlled build environment to ensure consistency, and Cargo is used
for managing Rust packages.

- Docker: Follow the steps on the
  [Docker website](https://docs.docker.com/engine/install/) to install Docker
  for your platform. Once installed, ensure the Docker service is running
  following this guide further.
- Cargo: If you don’t already have Cargo installed, you can install it by
  running the following command:

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

</Step>
<Step>

### Install the Solana Verify CLI

The Solana Verify CLI is the primary tool used to verify builds. Solana Verify
CLI is currently maintained by [Ellipsis Labs](https://ellipsislabs.xyz/) and
can be installed using Cargo.

You can install it by running:

```bash
cargo install solana-verify
```

If you need a specific version of the CLI, you can pin the version with:

```bash
cargo install solana-verify --version $VERSION
```

If desired, you can install a version directly from a specific commit:

```bash
cargo install solana-verify --git https://github.com/Ellipsis-Labs/solana-verifiable-build --rev 13a1db2
```

</Step>
<Step>

### Prepare project

To verify against a repository it needs to have a `Cargo.lock` file in the root
directory of your repository. If you only have one program in your repository
and a `cargo.lock` file in your root you can directly go to the next step and
build your program.

If your program is in a subfolder and you have a rust workspace you need to
create a workspace `Cargo.toml` file in the root directory of your repository.

You can use this `Cargo.toml` example as a preset:

```toml title="Cargo.toml"
[workspace]
members = ["program/programs/*"]
resolver = "2"

[profile.release]
overflow-checks = true
lto = "fat"
codegen-units = 1

[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
```

Make sure that your program is in the `workspace/members` array and that the
`Cargo.toml` of your program has the correct `lib` name configured.

> Important is the `lib name` not the package name!

Something like this:

```toml title="waffle/Cargo.toml"
[package]
name = "waffle"
version = "0.1.0"
edition = "2021"

[lib]
name = "waffle"
crate-type = ["cdylib", "lib"]

[dependencies]
solana-program = "2.1.0"
```

In this [repository](https://github.com/solana-developers/verified-program) you
can see an example of a workspace with a program in a subfolder. Notice also
that when the program is in a subfolder you later need to add this folder as
`--mount-path` to the `verify-from-repo` command.

In this [repository](https://github.com/solana-developers/solana-game-preset)
you can find an anchor example. In this
[repository](https://github.com/solana-developers/verified-program-root) you can
find a native rust example.

With this `Cargo.toml` file in place you can then run `cargo generate-lockfile`
to create a lock file and continue to building your program.

</Step>
<Step>

### Building Verifiable Programs

To verifiably build your Solana program, navigate to the directory containing
your workspace's `Cargo.toml` file and run:

```bash
solana-verify build
```

This will copy your environment into a docker container and build it in a
deterministic way.

> Make sure that you actually deploy the verified build and don't accidentally
> overwrite it with `anchor build` or `cargo build-sbf` since these will most
> likely not result into the same hash and though your verification will fail.

For projects with multiple programs, you can build a specific program by using
the library name (not the package name):

```bash
solana-verify build --library-name $PROGRAM_LIB_NAME
```

This process ensures deterministic builds and can take some time, especially on
certain systems (e.g., M1 MacBook) because it is running within a docker
container. For faster builds, using a Linux machine running x86 architecture is
recommended.

Once the build completes, you can retrieve the hash of the executable using the
following command:

```bash
solana-verify get-executable-hash target/deploy/$PROGRAM_LIB_NAME.so
```

</Step>
<Step>

### Deploying Verifiable Programs

Once you have built your program and retrieved its hash, you can deploy it to
the Solana network. It is recommended to use a multi-signature or governance
solution like [Squads Protocol](https://squads.so/protocol) for safe
deployments, but you can also directly deploy with:

```bash
solana program deploy -u $NETWORK_URL target/deploy/$PROGRAM_LIB_NAME.so --program-id $PROGRAM_ID --with-compute-unit-price 50000 --max-sign-attempts 100 --use-rpc
```

A currently fitting low priority fee you can request from your rpc provider for
example [Quicknode](https://www.quicknode.com/gas-tracker/solana).

To verify the deployed program matches the built executable, run:

```bash
solana-verify get-program-hash -u $NETWORK_URL $PROGRAM_ID
```

> You may have different versions deployed on different
> [Solana clusters](/docs/references/clusters) (i.e. devnet, testnet, mainnet).
> Ensure you use the correct network URL for the desired Solana cluster you want
> to verify a program against. Remote verification will only work on mainnet.

</Step>
<Step>

### Verifying against repositories

To verify a program against its public repository, use:

```bash
solana-verify verify-from-repo -u $NETWORK_URL --program-id $PROGRAM_ID https://github.com/$REPO_PATH --commit-hash $COMMIT_HASH --library-name $PROGRAM_LIB_NAME --mount-path $MOUNT_PATH
```

> While you run the verified build in your program directory, when running
> `verify-from-repo` you need to add the `--mount-path` flag. This will be the
> path to the folder containing the `Cargo.toml` that contains your program's
> library name.

This command compares the onchain program hash with the executable hash built
from the source at the specified commit hash.

At the end the command will ask you if you want to upload your verification data
onchain. If you do that the Solana Explorer will immediately show your program's
verification data. Until it was verified by a remote build it will show as
unverified. Learn how you can verify your program against a public API in the
next step.

If you want to lock the verification to a certain release, you can append the
`--commit-hash` flag to the command.

</Step>
<Step>

### Verify against public API

After you upload your verification PDA onchain with `verify-from-repo`, submit a
remote verification job to the
[OtterSec API](https://github.com/otter-sec/solana-verified-programs-api):

```bash
solana-verify remote submit-job --program-id <program-id> --uploader <address>
```

The `--uploader` is the address that uploaded the verification PDA, usually your
program's upgrade authority. If your program is controlled by a multisig,
continue in the
[multisig verification](#how-to-verify-your-program-when-its-controlled-by-a-multisig-like-squads)
part of this guide below.

> The legacy `--remote` flag on `verify-from-repo` has been deprecated. Upload
> your PDA first, then run `remote submit-job`.

This submits a job to the OtterSec API. You can check the job status with:

```bash
solana-verify remote get-job --job-id <job-id>
```

Once the verification has completed successfully, which may take awhile, you
will be able to see your program as verified in the
[OtterSec API for single programs](https://verify.osec.io/status/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY)
and in the
[Solana Explorer](https://explorer.solana.com/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY/verified-build),
[SolanaFM](https://solana.fm/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY?cluster=mainnet-alpha),
[SolScan](https://solscan.io/account/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY#programVerification)
and eventually also on the community-run website
[SolanaVerify.org](https://www.solanaverify.org/) maintained by
[0xDeep](https://x.com/0xDeep) and the
[OtterSec verified programs API](https://verify.osec.io/verified-programs) and
at last in the
[Verified Programs Dune Dashboard](https://dune.com/jonashahn/verified-programs/dedf21e1-9b71-42c8-89f9-02ed94628657)
contributing to a more healthy Solana ecosystem.

</Step>
</Steps>

## How to verify your program when its controlled by a Multisig like Squads

For the remote verification to work you need to write the verification data into
a PDA signed by the program authority. If your program is controlled by a
multisig you can export this write PDA transaction and submit it through
[Squads Protocol](https://squads.so/protocol) or another multisig solution of
your choice.

<Steps>
<Step>

### 1. Build the verifiable program

First build the program:

```bash
solana-verify build
```

This will build a verifiable build using a docker container using the solana
version specified in the `Cargo.lock` file.

</Step>
<Step>

### 2. Deploy the program

```bash
solana config set --url "PayedMainnetRPCAddress" // the public endpoint will be rate limited too much
solana program deploy target/deploy/verify_squads.so
```

For the rest of this multisig guide, we will use an example program ID of
`6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD`.

</Step>
<Step>

### 3. Commit and verify against repository

Once that is done we commit the project to to github. Here is an example:
https://github.com/solana-developers/verify-squads

Optional: See if you can verify locally first (this command uses example program
ID `6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD`):

```bash
solana-verify verify-from-repo https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD
```

Just to make sure your parameters are correct.

</Step>
<Step>

### 4. Transfer program authority to multisig

If you have not yet transfer your programs authority to the multisig and copy
the multisig authority. You need it in the next step.

</Step>
<Step>

### 5. Export PDA transaction

When you have you program authority locally you are prompted to upload the build
data onchain when using the command `solana-verify verify-from-repo`.

Since you can not do that when you are using a multisig you need to export the
PDA transaction manually and then trigger the transaction through Squads.

```bash
solana-verify export-pda-tx https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader <your program authority> --encoding base58 --compute-unit-price 0
```

This will return you a base58 transaction. If you want a base64 encoded
transaction for use in a transaction inspector, you can use `--encoding base64`.

```bash
P6vBfcPaaXb8fZoT3NBAYEcdtEj7tubA1k2gBxmFKZ3UWF5YyrmDMFTvLKALCJoUuRsPAjMckudYruCu3eeWQtuDrFbEMLxLFutnKXac974fnkMivcwUdY66VLjbxQT6ATmcy7F4hBtz1G4P1h6iBJLhb8WtrtgY3i4qq45MUEb7RjuMEfUFXKrNgPdGxkz5xvMHq3dxKRcpmEK5k2DkeW6SUQYBVe19Ga3B9GyhTX8k3CMt9JCEah13WyRnQd8GjoK6sTEvGJym6xDNvmd8yiJYSNcaYwEJsjHEUf4Yh6kAC7ki2KRvVAr3NVe1gjqK9McrwSQjtUatvydTG8Zovcr7PPUEMf3yPMgKXjZLB2QpkH63yTTYdNAnWFuv9E6b6nYRqye5XcNi436yKw5U14fXh65yK34bgYLi9328UT1huJELsJU9BRGnGUmb6GWp6c2WL5BhnzgNTSnt9TXFfEgUMzhvKzpVBxLP44hwqqBdyUhHFysCF37531PnmiESq8x1xou23xJ6FcQbc199754MkqQd7tX9CUznGzAEqHGkzn3VBoJnojsKtgYmiTYbdRsT1CU18MbYEE7WvGAvXyxxbpNzbAcc94HrnM6cqRGmwhEBroPfFghTdmzg9D
```

</Step>
<Step>

### 6. Submit transaction through Squads

Go to the squads transaction builder and import the base58 encoded transaction.
Make sure that in the simulation the transaction only has a call to the osec
verify program and the computer budget program and nothing else!

</Step>
<Step>

### 7. Submit remote verification job

Once the transaction to squads was successful you can submit the remote job:

```bash
solana-verify remote submit-job --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD
--uploader <your program authority>
```

This is it! You have verified your program against a public repository and
submitted a remote job to the OtterSec API. You should be able to see it reflect
in the solana explorer and other places now.

</Step>
<Step>

### 8. Updating the program (Optional)

When you update your program you need to export a new PDA transaction and submit
it through Squads again.

Doing an update to the program:

```bash
solana-verify build
solana program write-buffer target/deploy/verify_squads.so --with-compute-unit-price 50000 --max-sign-attempts 50
```

Then transfer that buffer authority to the multisig or directly create the
buffer with the authority of the multisig.

```bash
solana program set-buffer-authority Fu3k79g53ZozAj47uq1tXrFy4QbQYh7y745DDsxjtyLR --new-buffer-authority 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
```

</Step>
<Step>

### 9. Export and submit new PDA transaction

Don't forget to commit your changes to github. Export the PDA upgrade
transaction again:

```bash
solana-verify export-pda-tx https://github.com/solana-developers/verify-squads --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
```

Submit the transaction through Squads again.

You can see an example transaction
[here](https://solana.fm/tx/4zJ1vK2KToAwxuEYzTMLqPkcebjoi9rdeeyxtEEx9L5Q4vWDA8h6Rr4kPRuRxcV7ZLKMr6qx1LTWb6x3ZpUJaFUW?cluster=mainnet-alpha).

Then submit for another remote build:

```bash
solana-verify remote submit-job --program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD --uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K
```

Should result in something like this:

```shell
Verification request sent with request id: b63339d2-163e-49ac-b55d-3454c1c2b5b3
Verification in progress... ⏳ [00:18:02] ✅ Process completed. (Done in 18
minutes) Program 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD has been verified.
✅ The provided GitHub build matches the onchain hash. On Chain Hash:
96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 Executable
Hash: 96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 Repo URL:
https://github.com/Woody4618/verify-squads/tree/0fb0a2e30c15c51732c0ad5e837975a6f7bbc7ed
Check the verification status at:
https://verify.osec.io/status/6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD Job
url: https://verify.osec.io/job/b63339d2-163e-49ac-b55d-3454c1c2b5b3
```

Congratulations you have verified your program after a multisig upgrade!

</Step>
</Steps>

## Verify from docker image

You can also verify your program against a docker image by running the following
command:

```bash
solana-verify verify-from-image -e
examples/hello_world/target/deploy/hello_world.so -i
ellipsislabs/hello_world_verifiable_build:latest -p
2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn
```

This command loads up the image stored at
`ellipsislabs/hello_world_verifiable_build:latest`, and verifies that the hash
of the executable path in the container is the same as the hash of the onchain
program supplied to the command. Because the build was already uploaded to an
image, there is no need for a full rebuild of the executable which can take a
long time.

The Dockerfile that creates the image
`ellipsislabs/hello_world_verifiable_build:latest` can be found in the ellipsis
labs repository
[/examples/hello_world](https://github.com/Ellipsis-Labs/solana-verifiable-build/tree/master/examples/hello_world).

Below is the expected output:

```bash
Verifying image: "ellipsislabs/hello_world_verifiable_build:latest", on network
"https://api.mainnet.solana.com" against program ID
2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn Executable path in container:
"examples/hello_world/target/deploy/hello_world.so"

Executable hash:
08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Program hash:
08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Executable
matches onchain program data ✅
```

## Example verified build

Here’s an example of verifying an example program with the ID
`FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv` using the source code from this
[repository](https://github.com/solana-developers/verified-program):

```bash
solana-verify verify-from-repo https://github.com/solana-developers/verified-program --url YOUR-RPC-URL --program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv --mount-path waffle --library-name waffle --commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e
```

By default the `verify-from-repo` command takes the last commit on the main
branch. You can also define a certain commit in case you want to continue
working on the repository by using the `commit-hash` parameter:
`--commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e`

When prompted, answer yes to upload your verification PDA onchain. Then submit a
remote verification job against the OtterSec API:

```bash
solana-verify remote submit-job --program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv --uploader <your-upgrade-authority>
```

## Popular programs that are already verified

### Phoenix

```shell
solana-verify verify-from-repo -um --program-id PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY https://github.com/Ellipsis-Labs/phoenix-v1
```

Final Output:

```shell
Executable Program Hash from repo: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9
Onchain Program Hash: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9
Program hash matches ✅
```

### Squads V3

```shell
solana-verify verify-from-repo https://github.com/Squads-Protocol/squads-mpl --commit-hash c95b7673d616c377a349ca424261872dfcf8b19d --program-id SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu -um --library-name squads_mpl --bpf
```

> Notice we needed to specify the `library-name` because the Squads repo
> includes multiple programs. We use the `--bpf` flag because `squads_mpl` was
> previously verified with Anchor.

Final Output:

```shell
Executable Program Hash from repo: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c
Onchain Program Hash: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c
Program hash matches ✅
```

### Drift V2

```shell
solana-verify verify-from-repo -um --program-id dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH https://github.com/drift-labs/protocol-v2 --commit-hash 110d3ff4f8ba07c178d69f9bfc7b30194fac56d6 --library-name drift
```

Final Output:

```shell
Executable Program Hash from repo: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828
Onchain Program Hash: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828
Program hash matches ✅
```

### Marginfi V2

```shell
solana-verify verify-from-repo -um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA https://github.com/mrgnlabs/marginfi-v2 --commit-hash d33e649e415c354cc2a1e3c49131725552d69ba0 --library-name marginfi -- --features mainnet-beta
```

Final Output:

```shell
Executable Program Hash from repo: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5
Onchain Program Hash: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5
Program hash matches ✅
```

# Frequently asked questions

## My verification is failing. What should I do?

Check these common issues:

- **Wrong signer**: Confirm your signer is the program's upgrade authority by
  running `solana program show YourProgramId`
- **No onchain PDA**: Run `solana-verify verify-from-repo -um` and **select YES
  when prompted**. Without uploading the PDA, the API can't retrieve your
  verification metadata.
- **PDA data mismatch**: Update your PDA if you've redeployed your program. Your
  PDA data must match your deployed program.
- **Incorrect commit hash**: Create your PDA using the exact commit hash you
  deployed
- **Build environment differences**: Use Docker with solana-verify when creating
  your PDA

## My local build hash doesn't match the onchain hash. Why?

This usually means:

- You're using different Rust/Solana toolchain versions
- Your dependencies were updated between builds
- You didn't build in a Docker container
- You checked out the wrong commit

Fix this by building with `solana-verify build` in Docker using the exact commit
you deployed.

## How long will my verification take?

Expect these timeframes based on your program size:

- Simple programs: 1-5 minutes
- Complex programs: 5-15 minutes
- Very large programs: Up to 30 minutes

Track your progress using the job status endpoint.

## My program is immutable (no upgrade authority). How can I verify it?

If your program has no upgrade authority or was made immutable before you could
create a PDA, we have a whitelisted address for this situation. Contact us at
contact@osec.io, and we'll help you get your program verified.

## What is the PDA and why does it matter?

Your PDA (Program Derived Account) enables trustless verification:

- **On-Chain Storage**: Store your verification metadata (repo URL, commit hash,
  build params) onchain in a PDA owned by the Otter Verify program
  (`verifycLy8mB96wd9wqq3WDXQwM4oU6r42Th37Db9fC`)
- **Cryptographic Link**: Your PDA is derived from your program address,
  creating an immutable link to your verification data
- **Decentralized Trust**: Anyone can read your PDA and independently verify
  your program

## Why must I create the PDA before using the API?

The API only works with onchain PDAs because:

- **Trustless**: The API rejects arbitrary data - it only uses what your upgrade
  authority stored onchain
- **Simpler**: Just provide signer + program_id; the API gets everything else
  from your PDA
- **Tamper-Proof**: Your PDA creates an immutable record anyone can verify
  independently
- **Ownership Proof**: Your signer must be the upgrade authority,
  cryptographically proving you control the program

## How often should I verify my program?

Verify your program:

- After every deployment or upgrade
- When you update your source repository
- Don't worry about re-verifying otherwise - the API automatically re-verifies
  all programs every 24 hours

## What happens when I upgrade my program?

Follow these steps after upgrading:

1. The API detects your upgrade and unverifies your program.
2. Update your PDA with new verification metadata:

```bash
solana-verify verify-from-repo -um \
  --program-id YourProgramId... \
  https://github.com/your-org/your-program
```

3. Submit a new verification request using your upgrade authority
4. The API will verify your new version against the updated PDA

**Important**: Always update your PDA using your upgrade authority with the new
commit hash for the upgraded program.

## Can I trust the verification results?

Yes - the system is designed to be trustless and independently verifiable:

**What Makes It Trustworthy:**

- **On-Chain PDA**: Your verification metadata lives onchain, not controlled by
  any central authority
- **Upgrade Authority Proof**: Only your program's upgrade authority can
  create/update the PDA
- **Independent Verification**: Anyone can verify by reading your PDA and
  running `solana-verify` locally
- **Continuous Re-verification**: The API automatically re-verifies all programs
  every 24 hours

**Understand These Limitations:**

- Verification confirms source matches deployment - **NOT** that your code is
  secure
- Always review code before interacting with programs
- Verified ≠ audited, or safe
- Check the repository and commit in the PDA to confirm it's from a trusted
  source

## How can I independently verify a program?

Verify any program yourself by reading its onchain PDA and running verification
locally:

**Step 1: Read the On-Chain PDA**

```bash
# Install solana-verify if you haven't
cargo install solana-verify

# Get the PDA data
solana-verify list-program-pdas --program-id YourProgramId...
```

**Step 2: Verify Locally**

```bash
# Verify using the repository and commit & other arguments from the PDA
solana-verify verify-from-repo \
  --program-id YourProgramId... \
  https://github.com/your-org/your-program
  --commit-hash <commit-hash>
  ... (other arguments from the PDA)
# Confirm the hash output matches the onchain program hash
```

**This proves:**

1. The PDA metadata is authentic (stored onchain)
2. The source code in the PDA's repository matches the deployed program
3. You don't need to trust the API - verify everything yourself onchain

## Can someone else verify my program without permission?

Yes, that's the reason why we require the signer to be the upgrade authority. We
only consider the verification to be valid if the signer is the upgrade
authority.

## What do I need to create verifiable builds?

Install these tools:

- Docker (for deterministic builds)
- Cargo (Rust package manager)
- Solana Verify CLI: `cargo install solana-verify`
- A public Git repository with your source code

## Can I verify private repositories?

No - verification requires public source code:

- Your PDA stores a public repository URL that anyone can access
- Trustless verification depends on public code access
- Users need to read your source code to understand what your program does
- The entire purpose is to let users independently verify source matches
  deployment

Private repositories break the verification system's core trust model.

## How do I verify a program controlled by Squads Multisig?

Follow these steps for multisig-controlled programs:

```bash
# 1. Build and deploy normally
solana-verify build
solana program deploy <your-program.so> --program-id YourProgramId...

# 2. Verify locally first - confirm the hash matches
solana-verify verify-from-repo -um \
  --program-id YourProgramId... \
  https://github.com/your-org/your-program

# 3. Export the PDA creation transaction
solana-verify export-pda-tx \
  --program-id YourProgramId... \
  https://github.com/your-org/your-program

# 4. Execute the PDA transaction through your Squads Multisig interface

# 5. After multisig execution, trigger remote verification
solana-verify remote submit-job \
  --program-id YourProgramId... \
  --uploader YourMultisigAddress...
```

**Critical**: Always verify locally (step 2) to confirm the build hash matches
before exporting the PDA transaction.

# Conclusion

Using [verified builds on Solana](/docs/programs/verified-builds) ensures the
integrity and trustworthiness of your programs on the network and allow
developers to find your SDKs directly from a Solana Explorer. By leveraging
tools like the Solana Verify CLI and Docker, you can maintain verifiable and
secure builds that align with your source code. Always take the necessary
precautions to use consistent environments, and consider governance solutions
for safe upgrades and deployments.

## Security + Disclaimer

While verified builds are a powerful tool for ensuring the integrity of your
Solana programs it is not completely trustless in the default setup. The docker
images are built and hosted by the Solana Foundation.

Be aware that you are building your project in a downloaded docker image and
that your whole setup gets copied into that docker image for building including
potentially sensitive information.

If you want to have a completely trustless setup you can build the docker images
yourself and host them on your own infrastructure. This way you can be sure that
the docker images are not tampered with. You can find the scripts to create your
own docker images in the
[Verified builds repository](https://github.com/Ellipsis-Labs/solana-verifiable-build)
and you can fork it and run the github actions yourself or validate that they
are correct.

Furthermore for the remote verification you are trusting the OtterSec API and
the
[Solana Explorer](https://explorer.solana.com/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY)
to a certain degree.

The API or Solana Explorer may potentially display incorrect information if
compromised.

If you want to have a completely trustless setup you can run the
[Verify API](https://github.com/otter-sec/solana-verified-programs-api) yourself
or run the program verification locally yourself using the `verify-from-repo`
command using the on chain verify data that is saved in a
[PDA](https://explorer.solana.com/address/63XDCHrwZu3mXsw2RUFb4tbNpChuUHx4eA5aJMnHkpQQ/anchor-account)
that is derived from the programs deploy authority and the
[verify program](https://explorer.solana.com/address/verifycLy8mB96wd9wqq3WDXQwM4oU6r42Th37Db9fC).

The verify program is deployed by the [OtterSec team](https://osec.io/) and is
not yet frozen so it can be upgraded at any time.

The Solana Foundation, OtterSec and the Ellipsis Labs team are not responsible
for any losses or damages that may occur from using the verified builds
pipeline.

# Security.txt for Solana programs

In addition to verified builds you can also add a `security.txt` file to your
program. In the future, once implemented, the `security.txt` will hold the
verifier public key for easy access to the verification data stored in the
verification PDA. The PDA containing all the information needed to build and
verify a program is derived from the programs address and the verifier pubkey.
By default this is the same pubkey that built and deployed the program. But it
can also be another pubkey that can be specified in the `security.txt`.

The `security.txt` feature allows developers to embed contact and security
information directly within their Solana smart contracts. Inspired by
[securitytxt.org](https://securitytxt.org), this approach provides a
standardized way for security researchers to reach out to project maintainers,
even if they only know the contract's address.

## Why use security.txt?

For many projects, especially smaller or private ones, identifying the
developers from just the contract address can be difficult and time-consuming.
Embedding a `security.txt` file within the program ensures that security
researchers can easily contact the correct people, potentially preventing
exploits and ensuring timely bug reports.

## How to implement security.txt

To add a `security.txt` to your Solana program, include the following steps:

Add the `solana-security-txt` dependency to your `Cargo.toml`:

```toml title="Cargo.toml"
[dependencies]
solana-security-txt = "1.1.1"
```

Use the `security_txt!` macro in your contract to define your security
information. You can include contact details, project URLs, and even a security
policy. Here's an example:

```rust
#[cfg(not(feature = "no-entrypoint"))]
use {default_env::default_env, solana_security_txt::security_txt};

#[cfg(not(feature = "no-entrypoint"))]
security_txt! {
    name: "MyProject",
    project_url: "https://myproject.com",
    contacts: "email:security@myproject.com,discord:security#1234",
    policy: "https://myproject.com/security-policy",

    // Optional Fields
    preferred_languages: "en,de",
    source_code: "https://github.com/solana-developers/solana-game-preset",
    source_revision: "5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r",
    source_release: "",
    encryption: "",
    auditors: "Verifier pubkey: 5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r",
    acknowledgements: "Thank you to our bug bounty hunters!"
}
```

Once the `security.txt` information is embedded in your program, it can be
easily queried via tools like the Solana Explorer, ensuring that your contact
and security details are available to anyone looking to report potential issues.

## Best practices

- Use Links: For information likely to change (e.g., contact details), it's
  recommended to link to a web page rather than hard-coding them into the
  contract. This avoids the need for frequent program upgrades.

- Verification: Before deploying, verify the format and content using the
  `query-security-txt` tool, which can validate both onchain programs and local
  binaries:

```bash
query-security-txt target/bpfel-unknown-unknown/release/my_contract.so
```

By embedding security contact information directly into your contract, you make
it easier for researchers to reach you, fostering better security and
communication within the Solana ecosystem.

This is
[an example of how security.txt looks in the Solana Explorer](https://explorer.solana.com/address/HPxKXnBN4vJ8RjpdqDCU7gvNQHeeyGnSviYTJ4fBrDt4/security?cluster=devnet)

The `security.txt` project is maintained by
[Neodyme Labs](https://github.com/neodyme-labs)

You can check verification status and browse verified programs at
[verify.osec.io](https://verify.osec.io).
