See what your confidential Move contract still reveals.
On Sui, Seal gates a decryption key behind a Move access policy; on Aptos, Confidential Assets keep balances and transfer amounts encrypted on-chain. But a single seal_approve that forgets to assert!, an amount emitted in an event, a decryption key handed to a sink, or the public amounts at a deposit can put private state back in the open. Kinetics reads a Move module and its confidentiality primitive, then traces every path a confidential value can take across the boundary. It runs entirely in your browser, before you deploy.
The in-browser tool is for exploring one module interactively. For a real project, the same rules run at the command line and in CI: Kinetics reads every .move file under the paths you give it, groups them by module, and analyzes the confidentiality surface of each — the reachability of each seal_approve policy and the flow of every confidential amount to an observable sink. Findings are reported at their true file and line, and it exits non-zero when a leak is present, so a pull request that would expose confidential state never merges.
Kinetics 0.4.0 — confidential · 2 file(s), 2 module(s) HIGH SEAL-OPEN sources/sealed_docs.move:17 Open policy — any caller can decrypt walrus_demo::sealed_docs::seal_approve never calls `assert!` or `abort`, so it completes for every caller: any address can obtain the key. fix: gate the policy — assert!(is_member(list, who), E_NO_ACCESS) — and let it abort for everyone else. MEDIUM CA-EVENT sources/confidential_pay.move:14 Confidential amount emitted in an event treasury::confidential_pay::pay emits PaidEvent{ to, amount }. An event field is plaintext to everyone who can read the transaction. high: 1 medium: 1 low: 0 info: 2 x Failing — a finding at or above high is present.
Flags let CI decide what matters: --fail-on medium tightens the gate, --min-severity hides advisory noise, and --disable SEAL-BIND,CA-BOUNDARY turns off individual rules. Emit machine-readable output with --sarif or --json. Point --chain sui or --chain aptos to fix the framework when a file mixes conventions; by default each module is classified from its own source.
See findings in the Security tab, on every pull request. Kinetics emits SARIF 2.1.0, the format GitHub code scanning renders natively. Add the Action and each finding appears inline on the pull request and in the repository's Security tab, annotated on the exact line and linked to the rule that raised it.
# .github/workflows/confidentiality.yml name: Confidentiality on: [pull_request] permissions: contents: read security-events: write # upload SARIF to code scanning jobs: kinetics: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: choosek/kinetics-ts@v0 with: path: sources fail-on: high
The Action runs the analysis, uploads the SARIF report so results always reach code scanning, then enforces the threshold as a separate step — so a blocked merge still leaves a full report behind to read.
Six Move modules a team might actually ship: three Sui Seal access policies and three Aptos Confidential-Asset modules. Four carry a distinct, realistic confidentiality defect; two are written correctly. Load any of them in the analyzer above.
How is analysis performed? Static analysis builds a model of your module's confidentiality surface — the reachability of each function and the flow of confidential state to the sinks that make it observable — and checks it against the rules the Seal and Confidential-Assets designs imply. It flags application-level leaks and misconfiguration; it does not analyze the key servers, the enclaves, or the cryptography themselves.
Who the policy admits
Each seal_approve policy is placed by what it does: Open (completes for any caller — the key is granted to everyone), Restricted (asserts a condition first), or Locked (always aborts — no one). Seal grants the key when a policy completes and denies when it aborts, so an Open policy is the same footgun as a public getter.
Where a confidential amount goes
An encrypted balance or amount is confidential on-chain. Kinetics propagates it forward to the sinks that disclose it — an argument in an emitted event, a returned or exported decryption key, the public amount at a deposit / withdraw — and reports the exact path.
Who you let look in
On Aptos, every transfer amount is also encrypted to the account's auditor viewing key, so a configured auditor decrypts everything — a mutable auditor is a trust change. On Sui, an upgradeable package's authority can replace a seal_approve policy after the fact. Both are surfaced.
Hashes are not leaks
A confidential value disclosed only through a cryptographic hash or commitment is recognized as such, not flagged as a leak — noted as a commitment, with the reminder that it is only as strong as the entropy of its pre-image.
It won't just cry "transfer"
A confidential_transfer that keeps its amount encrypted, or an Open function that moves value but never returns, emits, or exports it, reveals nothing. Kinetics distinguishes moving an encrypted value from disclosing it, so a clean module gets a clean bill, not noise.
Its own assumptions, stated
It models the published Seal and Confidential-Assets designs, not a live deployment, and lists its assumptions with every run. It parses the source to a Move AST and traces information flow through calls, falling back to a lexical scan on the rare construct the parser does not yet cover; where behavior needs confirming (package upgradeability, the configured auditor) it flags for review rather than asserting.
One rule set, wherever it runs. The analyzer parses Move to an AST — resolving modules and following dataflow through calls, so a policy whose check lives in a helper reads as Restricted and a hashed amount reads as a commitment, not a leak. The engine ships in the @choosek/kinetics library, so this page, the kinetics confidential command line, and the GitHub Action all agree on every finding. The rules below are the catalog the engine checks.