# Orbit Station Audit

> Build and run the Orbit station configuration audit (`orbit-cli audit`) end-to-end against a live station, including the icp-cli Internet Identity setup that reliably trips people up. Use this whenever the user wants to audit, sanity-check, or security-review an Orbit station or wallet — e.g. "audit my Orbit wallet", "run orbit-cli audit on station <canister-id>", "check my Orbit station for misconfigured approval policies / empty quorums", or any time they pair an Orbit station canister id with auditing, approval quorum, or permission checks. Reach for this even if they don't say "orbit-cli" by name. It covers building the CLI from source (the globally installed orbit-cli is usually too old to have the `audit` subcommand), obtaining an identity the station recognizes as a member, and reading the report.

- Skill: `dfinity/orbit-station-audit` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add dfinity/orbit-station-audit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dfinity/orbit-station-audit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: dfinity (https://skillmd.com/u/dfinity)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/dfinity/orbit-station-audit

---


# Orbit station audit

`orbit-cli audit` runs read-only sanity checks against a live station and
prints a severity-sorted report — safe to run any time, since it only issues
`list_*` queries and mutates nothing. Flags, exit codes, and report format are
documented in [`cli/src/audit/README.md`](../../../cli/src/audit/README.md);
read that for reference. This skill is the *operational* guide — it gets you
from a fresh checkout to a successful run and front-loads the three things that
actually derail a first one.

## The three gotchas (read these first)

1. **Don't rely on the global `orbit-cli`.** A global on `PATH` may be from an
   older checkout that predates the `audit` subcommand (unknown-command error).
   Build and run this repo's `cli/dist/cli.js` instead — what the helper script
   does — so there's no doubt about which version you're invoking.
2. **Internet Identity principals are per-origin.** The same II anchor yields a
   *different* principal for every app origin. The audit must be called by a
   principal the station knows as a member, so the identity has to be derived
   from the origin the wallet itself uses. In production that origin is
   **`orbitwallet.io`** (pinned as `derivationOrigin` in
   [`apps/wallet/src/configs/init.config.ts`](../../../apps/wallet/src/configs/init.config.ts)),
   *not* the URL bar. Pass the bare host `orbitwallet.io` to `--app` (no
   `https://`, even though the config shows a scheme). Deriving from anything
   else (`app.orbit.global`, `oisy.com`, the default `cli.id.ai`) gives a
   stranger principal that the station will reject.
3. **`icp identity link web` waits for an Enter keypress** before it opens the
   browser. Running it non-interactively, pipe a newline in so it proceeds:
   `printf '\n' | icp identity link web ...`. The human still completes the
   actual sign-in in the browser.

## Prerequisites

- Node 20 and pnpm 9 (the repo pins `pnpm@9.12.2` via `packageManager`;
  Corepack normally handles this).
- `icp-cli` on `PATH` (`brew install icp-cli`, or
  <https://internetcomputer.org/install>) — needed for `--identity-source icp`.
- A working copy of the Orbit repo. If you aren't in one:
  `git clone https://github.com/dfinity/orbit && cd orbit`.

## Step 1 — Build the CLI from source

The helper script does this for you (install if needed → build → run), so
prefer it:

```bash
.claude/skills/orbit-station-audit/scripts/run-audit.sh --help
```

Equivalent by hand, if you'd rather see each step:

```bash
pnpm install                       # once, if node_modules is missing
pnpm --filter orbit-cli build      # emits cli/dist/cli.js
node cli/dist/cli.js audit --help
```

Run the freshly built `cli/dist/cli.js` directly so there's no doubt about
which build is on `PATH`.

## Step 2 — Get an identity the station recognizes

The audit signs its calls with an identity that must be a station **member**
(admin-tier users have the required read access by default). For an
Internet-Identity-based wallet, that means an `icp-cli` identity derived from
`orbitwallet.io` (gotcha 2).

First, reuse an existing one if you already have it:

```bash
icp identity list
icp identity principal --identity <name>   # for each plausible candidate
```

If a candidate's principal already matches the principal shown in your wallet
UI under **Settings → Identity**, use that name and skip to Step 3. (Identities
bound to other origins — `oisy.com`, the default `cli.id.ai` — will *not* match.)

Otherwise create one bound to the wallet's origin:

```bash
printf '\n' | icp identity link web orbit-audit --app orbitwallet.io
icp identity principal --identity orbit-audit
```

A browser opens to `id.ai`. **Sign in with the same Internet Identity anchor
you use to log into Orbit.** The printed principal should match your wallet's
Settings → Identity. The *definitive* test, though, is Step 3: if the audit's
read calls are authorized, you are a member.

If the principal doesn't match (or Step 3 returns an authorization error),
delete it and re-link trying a different origin or anchor:

```bash
icp identity delete orbit-audit          # note: `delete`, not `remove`
printf '\n' | icp identity link web orbit-audit --app app.orbit.global
```

`orbitwallet.io` is correct for the current production wallet; `app.orbit.global`
is the fallback to try if the station predates that derivation origin.

## Step 3 — Run the audit

```bash
.claude/skills/orbit-station-audit/scripts/run-audit.sh \
  --station <STATION-CANISTER-ID> \
  --identity orbit-audit \
  --identity-source icp \
  --output ~/Downloads/orbit-audit-$(date +%F).txt
```

Every flag after the script name is forwarded verbatim to `orbit-cli audit`, so
swap in whichever identity matched in Step 2. `--network` defaults to `ic` (pass
`--network local` for a local replica), and dropping `--output` prints to
stdout. `--output` writes internal station metadata (principals, policy ids) —
keep it private. Exit code `2` means at least one blocker (full table in the
README).

## Troubleshooting

- **`Unauthorized` / read calls rejected** — the calling principal isn't a
  station member. Re-check Step 2: right anchor, right `--app` origin, and the
  principal actually matches your wallet UI.
- **`icp identity store not found`** — `icp-cli` isn't installed, or you used
  `--identity-source icp` without it. Install icp-cli, or fall back to a dfx PEM
  with `--identity-source dfx` (use a *plaintext* identity — passphrase-protected
  PEMs aren't supported; see the README).

