See what your Midnight contract makes public.

A map key, a branch on a secret, a hash of a 4-digit PIN: on Midnight they all leak information, and none of it is obvious from reading the code. Compact X-Ray asks the official compiler, and shows every private value that reaches the chain, how much of it, and through which line.

$ compact-xray private-bid.compact IN PLAIN WORDS ● When the contract is deployed, anyone watching the chain learns the exact minimum in minimumBid. ● When someone calls placeBid, anyone watching the chain learns a fingerprint (hash) of the private value localSecretKey in bidCommitments. STAYS PRIVATE ✓ placeBid(amount) PRIVACY POLICY ✗ not in policy: placeBid: arg amount -> ledger revealedBids

Nothing is guessed. The compiler says it.

X-Ray does not re-implement Compact's privacy rules, so it cannot drift from them. It uses the compiler as the oracle.

01

Remove every disclose()

A copy of your contract with each disclose( blanked out, character for character, so every line and column stays where it was.

02

Let the compiler object

It now rejects each place a private value would reach the public side, naming the value, how much of it leaks, and the path it takes.

03

Read it as a map

Private inputs on one side, public state and token operations on the other, one line per disclosure, coloured by how much leaks.

exact valuehashdecisioncomputation

What we measured

Run against the compiler (0.31.1) and a local Midnight network (ledger 8). Some of it contradicts the docs.

🔁
Return values are not published.The compiler demands disclose() to return a witness value, but a probe contract showed the returned value is not in the transaction on chain; it goes back to the calling DApp.
🗝️
Ledger lookups are public.A key used only in m.member(k) inside an assert must still be disclosed.
🔀
Branches on secrets leak.if (secret > 5) {a = 1} else {a = 2} reveals the decision; the compiler tracks control flow.
🧹
18 unnecessary disclose() calls in the official examples.Mostly inside assert comparisons, which only reveal pass/fail. --deep finds them by removing one at a time.

Use it where you work

The same analysis behind every surface.

CLI

Report, init a privacy policy, check it, diff two versions. Text, JSON, Markdown, SARIF, HTML.

GitHub Action

Fails a pull request that makes a private value newly public, with findings inline on the diff.

VS Code

On save: each disclosing line marked, warnings for risky patterns, and what each circuit publishes above it.

# .github/workflows/privacy.yml
- uses: actions/checkout@v4
- uses: elaris-xyz/Compact-X-Ray@v0
  with:
    contracts: contracts/**/*.compact
    compact-version: 0.31.1
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with: { sarif_file: compact-xray.sarif }