Skip to Content
GuidesVerify your installation
Guides & contentsIn this article

Verify your ConnectBot installation

You can check that the ConnectBot code installed on your phone was signed with ConnectBot’s keys. You can also connect that code to a particular GitHub build and source commit.

Choose the instructions for Google Play or GitHub Releases below. These checks apply to releases that include code transparency; older releases may not include it. F-Droid builds use a separate distribution process and are outside this guide.

What you will check

CheckWhat a successful result establishes
APK signatureThe installed APKs are intact and their signing certificate matches the trusted certificate for your download channel.
Code transparencyInstalled DEX bytecode and native libraries match a statement signed with ConnectBot’s transparency key.
Build provenance (optional)The matching release artifact is authenticated by ConnectBot’s GitHub release workflow, which records its source commit and build run.

Start with the installed-app checks. The optional provenance steps then connect the installed code to an authenticated release artifact. Matching version numbers alone do not establish that connection.

Prepare your computer and phone

  1. Install Java , Android platform-tools , and bundletool . Use the Java version required by your bundletool release, and save its executable JAR as bundletool.jar in a new working folder.
  2. Make sure java and adb are available in your terminal. On Windows, use a Bash terminal such as Git Bash for the command examples; install Windows platform-tools and add its folder to PATH.
  3. Enable Developer options, then USB debugging on your Android device. Connect it to your computer, unlock it, and accept the debugging authorization prompt. See Android’s device setup instructions .
  4. Run the following command. Your device should appear with status device:
adb devices -l

Use one connected device throughout the walkthrough. If several devices or emulators are listed, select one in your terminal with export ANDROID_SERIAL='YOUR_DEVICE_SERIAL' before continuing. Bundletool and the later adb commands will use it.

Find ConnectBot’s installed version in Android’s Settings → Apps → ConnectBot app information screen. You can also inspect its version name and version code with:

adb shell dumpsys package org.connectbot

Keep the installed version unchanged while completing the checks. Use a fresh working folder for each release, containing your tools, certificates, and downloads. Run one command block at a time and stop if it reports an error. The explanations below identify the files each command reads or writes.

For the download and build-provenance commands, enter the release tag matching your installation. The filenames in those commands update as you type.

Use the exact GitHub release tag, such as v1.11.1 or git-v1.11.1-3-g670d06ef.

Download the trusted certificates

Download the transparency certificate and the APK-signing certificate for your channel into your working folder. Preserve the filenames shown here.

CertificateDownloadSHA-256 certificate fingerprint
Code transparency, both channelsconnectbot-transparency.pem909e650add6ddce32b2307d5aa141f8cdb1bdf455d89388b2f53f8c30fdb0c61
Google Play app signingconnectbot-play-app-signing.pemaa43746a46127842169f8176412a1f4b1b1e2f8ad9e15aba217c3822dbeb2d5f
GitHub APK signingconnectbot-github-apk-signing.pemaa43746a46127842169f8176412a1f4b1b1e2f8ad9e15aba217c3822dbeb2d5f

The supplied Play and GitHub APK certificates currently have the same fingerprint, but serve separate distribution roles. The Play upload certificate is different: it authenticates uploads to Play, rather than the APKs Play installs on your phone.

Obtain these certificates from a trusted ConnectBot source. Extracting a certificate from the app you are checking does not independently establish who signed it. If you have OpenSSL, you can display a downloaded certificate’s fingerprint with:

openssl x509 -in connectbot-transparency.pem -noout -fingerprint -sha256

Compare the result with the table, ignoring colons and letter case. This is a certificate fingerprint, rather than a checksum of the PEM text file.

Check a Google Play installation

With the device connected, run:

java -jar bundletool.jar check-transparency \ --mode=connected_device \ --package-name=org.connectbot \ --apk-signing-key-certificate=connectbot-play-app-signing.pem \ --transparency-key-certificate=connectbot-transparency.pem

Check that bundletool reports all three results: the APK signature verifies against the supplied APK-signing certificate, the transparency signature verifies against the supplied transparency certificate, and the code files match the transparency statement. A successful command exits with status zero. Wording can vary between bundletool versions.

This checks the installed base APK and splits. To connect this code to its GitHub build, continue to Trace the installed code to a GitHub build.

Check a GitHub Releases installation

For ConnectBot installed from a GitHub release APK, run:

java -jar bundletool.jar check-transparency \ --mode=connected_device \ --package-name=org.connectbot \ --apk-signing-key-certificate=connectbot-github-apk-signing.pem \ --transparency-key-certificate=connectbot-transparency.pem

Require the same three successful results as the Play check: APK signature, transparency signature, and matching code files.

Check a downloaded APK before installing it

You can also verify a release APK on your computer. This checks the downloaded file; checking the installed copy still requires the connected-device command above.

You will need the zip utility. Set APK to the downloaded filename, then create downloaded-apks.zip containing that APK. Bundletool expects a ZIP of APKs for this mode:

APK='ConnectBot-{{release}}-oss.apk' zip downloaded-apks.zip "$APK" java -jar bundletool.jar check-transparency \ --mode=apk \ --apk-zip=downloaded-apks.zip \ --apk-signing-key-certificate=connectbot-github-apk-signing.pem \ --transparency-key-certificate=connectbot-transparency.pem

Enter a valid value for Release tag above to complete and copy this command.

Use a fresh ZIP: zip updates an archive if that filename already exists. Enter the release’s actual tag in the Release tag field. GitHub publishes oss and google variants; choose the file you downloaded. Stop if any check fails.

Trace the installed code to a GitHub build

This optional section requires GitHub CLI  (gh), jq  for reading JSON, and the unzip, sha256sum, and cmp utilities. On macOS, use shasum -a 256 -c in place of sha256sum --check below. On Windows, run these commands in Git Bash with these utilities installed. Authenticate with gh auth login if GitHub CLI requests it.

1. Get the matching release and evidence

Open ConnectBot’s releases  and find the release matching your installed version, including its version code. Download:

  • Its Google AAB (ConnectBot-…-google.aab) for a Play installation.
  • Its APK in the variant you installed (ConnectBot-…-oss.apk or ConnectBot-…-google.apk) for a GitHub installation.
  • Its signing evidence (ConnectBot-…-signing-evidence.zip).

If that release has no evidence archive, you cannot complete this provenance walkthrough for it. Do not substitute evidence from another release or an unsigned artifact.

Set ARTIFACT and EVIDENCE to the filenames you downloaded. These assignments only store filenames in your current shell:

ARTIFACT='ConnectBot-{{release}}-google.aab' EVIDENCE='ConnectBot-{{release}}-signing-evidence.zip'

Enter a valid value for Release tag above to complete and copy this command.

For GitHub installations, change ARTIFACT to your APK filename. Keep the files in your current folder and use their filenames without a directory prefix.

Extract only the manifest and attestation bundle from the evidence archive:

unzip "$EVIDENCE" release-manifest.json final.sigstore.json

unzip writes those two named files to the current folder. The evidence ZIP transports the original signed evidence; the ZIP’s presence on a release page does not authenticate its contents.

2. Authenticate the manifest and artifact

Run both commands and continue only if both succeed. They save the authenticated verification results for the next step:

gh attestation verify release-manifest.json \ --bundle final.sigstore.json \ --repo connectbot/connectbot \ --signer-workflow connectbot/actions/.github/workflows/android-finalize.yml \ --source-ref refs/heads/main \ --deny-self-hosted-runners \ --format json > manifest-verification.json gh attestation verify "$ARTIFACT" \ --bundle final.sigstore.json \ --repo connectbot/connectbot \ --signer-workflow connectbot/actions/.github/workflows/android-finalize.yml \ --source-ref refs/heads/main \ --deny-self-hosted-runners \ --format json > artifact-verification.json

These commands read the manifest, artifact, and attestation bundle, verify the signatures and digests, and enforce the expected repository, reusable signing workflow, source branch, and GitHub-hosted runner. Each > saves the verified JSON result in the named file. See the GitHub verification reference .

The finalizer runs from main even for tagged releases. Its GitHub certificate identifies the finalization workflow’s source; the Android app’s source commit is recorded separately in the authenticated release manifest. Do not replace the expected workflow identity with one copied from unverified evidence.

Check the signing workflow’s branch

The expected identity includes the trusted workflow’s branch. Store that exact identity, then check it against the authenticated certificate fields in both verification results:

IDENTITY='https://github.com/connectbot/actions/.github/workflows/android-finalize.yml@refs/heads/android-signer-v1' jq -s -e --arg identity "$IDENTITY" ' length == 2 and all(.[]; length > 0 and all(.[].verificationResult.signature.certificate; .buildSignerURI == $identity and .subjectAlternativeName == $identity ) ) ' manifest-verification.json artifact-verification.json

jq reads JSON; it does not execute the file’s contents. -s reads the two files together, and the expression requires both to contain verified attestations with the expected certificate identities. -e makes a failed comparison return a nonzero exit status. Expect true; stop on false or any error. This also rejects empty verification results.

Check the artifact against the manifest

Read the expected SHA-256 for your filename from the authenticated manifest and write it, alongside that filename, to a checksum file:

jq -er --arg file "$ARTIFACT" \ '.assets[$file].sha256 + " " + $file' \ release-manifest.json > artifact.sha256

--arg passes the filename as a string rather than treating it as part of the JSON query. The two spaces separate the expected digest from the filename in the standard checksum-file format. You can inspect the result:

cat artifact.sha256

Now calculate the downloaded file’s SHA-256 and compare it with that expected value:

sha256sum --check artifact.sha256

Expect your filename followed by OK. On macOS, run shasum -a 256 -c artifact.sha256 instead. Stop on a mismatch or an error.

Read the source commit and build run

Check that both repository fields name ConnectBot’s repository:

jq -e ' .repository == "connectbot/connectbot" and .source.repository == "connectbot/connectbot" ' release-manifest.json

Expect true. Then display the release tag, version codes, and Android source information:

jq '{release: .release.tag_name, version_codes, source}' release-manifest.json

Confirm that the release and your channel’s version code match your installation. The source object includes the commit, source ref, build run ID, and attempt. To print the corresponding build URL:

jq -r '"https://github.com/connectbot/connectbot/actions/runs/\(.source.run_id)/attempts/\(.source.attempt)"' release-manifest.json

These commands display claims authenticated by the trusted finalizer, which verifies the upstream build and signing evidence.

3. Copy the installed base APK

First complete the connected-device signature and transparency check for your channel above. That checks code across the installed APKs, including splits. For the statement comparison below, you need the base APK, which carries the signed transparency statement. See Android’s explanation of where the statement is stored .

Ask Android to list ConnectBot’s installed APK paths:

adb shell pm path org.connectbot

Find the line ending in /base.apk. Copy its full path, leaving off the package: prefix. Replace PASTE_BASE_APK_PATH_HERE below with that path, keeping the single quotes:

adb pull 'PASTE_BASE_APK_PATH_HERE' installed-base.apk

adb pull reads that file from your device and saves it as installed-base.apk on your computer. If ConnectBot updates during the process, repeat the installed-app check and copy the base APK again.

4. Compare the signed transparency statements

APKs and AABs are ZIP containers. unzip -p reads a particular entry from an archive; > saves those bytes to the named file. Run the command for your distribution channel below.

For a Google Play installation, extract the statement from the authenticated Google AAB:

unzip -p "$ARTIFACT" \ BUNDLE-METADATA/com.android.tools.build.bundletool/code_transparency_signed.jwt \ > release.jwt

For a GitHub installation, extract it from the authenticated release APK instead:

unzip -p "$ARTIFACT" META-INF/code_transparency_signed.jwt > release.jwt

Then extract the installed base APK’s statement:

unzip -p installed-base.apk META-INF/code_transparency_signed.jwt > installed.jwt

Require both extracted files to exist and contain data, then compare their complete bytes:

test -s release.jwt && test -s installed.jwt && cmp release.jwt installed.jwt echo $?

test -s checks that a file is nonempty. Each && runs the next check only if the preceding check succeeded. cmp compares the complete signed JWTs, without decoding or rewriting them. A match produces no output from cmp, and echo $? prints 0 for the preceding command’s success status. Any nonzero status means verification has not succeeded, even if no other message was printed. The nonempty checks prevent two missing or empty statements from being mistaken for a match.

Together with the successful installed-code check, a match connects your installed code to this authenticated release and its recorded build. Play generates device-specific APKs from an AAB, so comparing a whole installed APK’s SHA-256 with the release AAB’s SHA-256 would not work.

If verification fails

  • No device, or unauthorized: unlock the phone, check the USB connection, accept its authorization prompt, and run adb devices -l again. Select a serial if several devices are connected.

  • ADB cannot be found: add platform-tools to PATH, or pass bundletool --adb=/path/to/adb.

  • Java cannot run bundletool: check the Java requirement of the bundletool release you downloaded.

  • No transparency statement or signing evidence: older releases may predate these checks. Missing evidence means this walkthrough cannot verify them; it does not by itself prove tampering.

  • Certificate or signature mismatch: check your installation channel and the certificate filenames. Signing-key rotation or a Play key upgrade may require updated certificates and Android-version-specific instructions. Do not bypass a mismatch or trust a replacement certificate taken from the failing app.

  • Code hashes or JWTs differ: check the release, variant, and version code, then repeat after any app update has finished. Do not treat the installation as verified while the mismatch remains.

  • Attestation verification fails: check that the artifact and evidence came from the same release and that GitHub CLI can refresh its Sigstore trust data. A release produced by another workflow needs separately reviewed instructions; do not relax the identity checks to make it pass.

If you still need help, report the problem with the release, distribution channel, Android version, tool versions, and verification error.

What verification does and does not cover

Code transparency covers DEX bytecode and native libraries. It excludes resources, assets, and the Android manifest, and Android does not automatically enforce it during installation. The APK-signature check verifies APK integrity separately. See Android’s code-transparency documentation  for verification behavior and coverage.

A successful check establishes signing identity and a connection to a build. It does not establish that the source is free of vulnerabilities or independently reproducible. These instructions rely on a trusted Android system; they do not prove the integrity of a running process on a compromised device.

A website cannot inspect your installed apps directly, and ConnectBot does not currently provide a separate on-phone verifier. Checking an uploaded or downloaded APK establishes facts about that file, rather than establishing that it is the installed copy.

When finished, you can disable USB debugging in Developer options and remove the temporary APK copies from your computer.

Last Updated
ConnectBot

Open-source SSH and Mosh client for Android

Links
GitHub RepositoryIRC Chat (#connectbot)Support DevelopmentPrivacy policy
© 2026 ConnectBot Contributors. Documentation licensed under CC BY 4.0.