# Nightshade documentation (full) > Every page of https://nightshade.dicksonwu.xyz as Markdown, for release 0.1.1 (v0.1.1). Pages are separated by lines of five equals signs and keep their canonical URL. # Nightshade > Nightshade is an offline static security analyzer for Midnight's Compact smart contracts. It follows private data to disclosures and ledger writes, checks guards alongside effects and runs in CI. Canonical: https://nightshade.dicksonwu.xyz/ Release: Nightshade 0.1.1 (v0.1.1) ## See where private data becomes public Nightshade is an offline static security analyzer for Midnight's Compact smart contracts. It follows private data to disclosures and ledger writes, checks guards alongside the effects they protect, and tells you what it could not analyze. Release v0.1.1, Apache-2.0, runs offline, experimental. Start with https://nightshade.dicksonwu.xyz/getting-started.md or browse the 96 rules at https://nightshade.dicksonwu.xyz/rules.md. ## Install The release targets Linux x86-64/glibc with Node 22 or 24 and libstdc++ providing `GLIBCXX_3.4.31` or newer (Ubuntu 24.04 or Debian 13). On macOS, use the Docker image from a source checkout. ```sh curl -fL https://github.com/DicksonWu654/nightshade/releases/download/v0.1.1/nightshade-compact-0.1.1.tgz -o nightshade-compact-0.1.1.tgz npm install --prefix ./.nightshade --no-audit --no-fund ./nightshade-compact-0.1.1.tgz ./.nightshade/node_modules/.bin/nightshade ./.nightshade/node_modules/nightshade-compact/examples/review/contract.compact --fail-on high ``` Installation needs network access. Scans run offline, do not execute contracts and do not need a Compact compiler. This first scan prints a medium finding and exits 0 because the threshold is high. ## Three findings, with their fixes Synthetic examples, scanned with the released 0.1.1 CLI. Command lines are shortened from the recorded runs; output paths are shortened to the example folder. All 10 examples: https://nightshade.dicksonwu.xyz/examples.md ### Private authentication preimage reaches the public ledger Synthetic example. Rule: [ledger-bound-preimage-publication](https://nightshade.dicksonwu.xyz/rules/ledger-bound-preimage-publication.md), severity medium. A secret checked against a stored hash is then written directly to public state. vulnerable.compact: ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Field; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(secret); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Ledger-bound private preimage is published [ledger-bound-preimage-publication] vulnerable.compact:12:3 12 | published = disclose(secret); | ^ Private value from ownerSecret reaches ledger-write published without a hiding transformation. A hash of this value is asserted equal to ledger ownerHash on the same potential successful path. Ledger operation data is public. If an untrusted observer obtains a reusable authentication secret through this boundary, secrecy is lost. An intentional reveal protocol may permit this flow. Source: vulnerable.compact:10:18 Constraint: vulnerable.compact:11:3 Call path: update Remediation: Keep reusable authentication preimages private; publish a suitable commitment or non-secret result. If this is intentional reveal, confirm that the revealed value grants no remaining authority and document that policy. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Publish the hash instead of the secret. The rule stays quiet (exit 0). Full example: https://nightshade.dicksonwu.xyz/examples.md#ledger-bound-preimage-publication ### The signature verification result is discarded Synthetic example. Rule: [ignored-validation-result](https://nightshade.dicksonwu.xyz/rules/ignored-validation-result.md), severity medium. The signature verifier returns a boolean, but the state change proceeds without asserting that it is true. vulnerable.compact, lines 16 to 25: ```compact // Synthetic regression mutation; no upstream-project finding is claimed. pragma language_version >= 0.20; import CompactStandardLibrary; export ledger round: Counter; export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); jubjubSchnorrVerify<1>(msg, sig, pk); round.increment(1); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Signature verification outcome is discarded [ignored-validation-result] vulnerable.compact:23:3 23 | jubjubSchnorrVerify<1>(msg, sig, pk); | ^ The Boolean outcome of the canonical jubjubSchnorrVerify is discarded. The call may impose internal constraints, but its signature-validity result does not constrain this caller through this use. Remediation: Assert the verification result, or reject the false branch before the transaction can succeed. Preserve intentional Boolean checker APIs; suppress intentional verifier-only tests with a reason. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Assert the verifier's result. The rule stays quiet (exit 0). Full example: https://nightshade.dicksonwu.xyz/examples.md#ignored-validation-result ### Two shielded mints reuse the same descriptor Synthetic example. Rule: [duplicate-shielded-mint](https://nightshade.dicksonwu.xyz/rules/duplicate-shielded-mint.md), severity medium. Two mint calls use identical token, amount, nonce and recipient inputs on the same path. vulnerable.compact: ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Duplicate shielded mint commitment [duplicate-shielded-mint] vulnerable.compact:7:3 7 | mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); | ^ rewardTwice invokes mintShieldedToken twice with provably identical token domain, amount, nonce and active recipient on one modeled successful history. The pinned library derives the same coin commitment in this contract context; duplicate commitments are rejected by the ledger. This is a transaction availability defect, not proof of token theft or a generic commitment-opening vulnerability. Source: vulnerable.compact:6:3 Call path: rewardTwice → mintShieldedToken Remediation: Use a distinct nonce for each minted output, for example evolveNonce with a distinct index. Review freshness across separate transactions independently. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Give the second mint a distinct nonce. The rule stays quiet (exit 0). Full example: https://nightshade.dicksonwu.xyz/examples.md#duplicate-shielded-mint ## Find a rule 96 rules, grouped by how they are selected and what they look at. Full list: https://nightshade.dicksonwu.xyz/rules.md. Catalog: https://nightshade.dicksonwu.xyz/rules.json. - [Audit defaults](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) (24 rules): Run on every scan: secret publication, authorization, signatures, time, mints, Merkle proofs. - [Policy rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) (13 rules): Check behavior against intent you declare, such as secret handling and authorization. - [Hygiene](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) (7 rules): Source quality checks added by --profile hygiene. - [Time and freshness](https://nightshade.dicksonwu.xyz/rules.md#time-and-freshness) (2 rules): Caller-supplied time, deadlines and chain-time bounds. - [Authorization and identity](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) (11 rules): Keys, signatures, membership and who may change state. - [Privacy and cryptography](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) (9 rules): Disclosure, commitments, hashes and derived secrets. - [Tokens and value](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) (13 rules): Shielded and unshielded coins, mints, sends and payouts. - [State and collections](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) (9 rules): Ledger writes, nullifiers, lists, maps and resets. - [Structure and validation](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) (8 rules): Assertions, conditions, dead code and validation results. ## Run it in CI The GitHub Action builds Nightshade, scans your workspace, uploads SARIF to code scanning and keeps the scan's exit code. Guide: https://nightshade.dicksonwu.xyz/github-action.md ```yaml name: Compact analysis on: [push, pull_request] permissions: contents: read security-events: write jobs: nightshade: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: DicksonWu654/nightshade@v0.1.1 with: path: contracts fail-on: medium category: compact-contracts ``` Excerpt of `--json` output for the first example, from the proof run (fields omitted, paths shortened): ```json { "toolVersion": "0.1.1", "status": "complete", "semanticProfile": "compact-0.34.0-zkir2", "findings": [ { "detectorId": "ledger-bound-preimage-publication", "severity": "medium", "confidence": "medium", "title": "Ledger-bound private preimage is published", "location": { "file": "vulnerable.compact", "line": 12, "column": 3 }, "callPath": [ "update" ], "fingerprint": "f13f49be2aab05165612212bfd4f1a1a7d06c4b9acd3d7ac66d4a4996a50b642", "metadata": { "pathFeasibility": "not-proven", "visibility": "public-ledger" } } ], "coverage": { "baselineStatus": "complete" } } ``` | Exit | Meaning with the default coverage policy | | --- | --- | | 0 | Complete analysis; no unsuppressed new finding meets the threshold | | 1 | Complete analysis; a finding meets the threshold | | 2 | Incomplete or invalid analysis, configuration error or worker failure | An incomplete scan exits 2 even with `fail-on: none`; it is never a clean result. ## What has been measured - **10 / 10 showcase findings fire.** 10 corrected versions and 9 lookalikes stay quiet. Synthetic, one rule per scan, compiler-validated. https://nightshade.dicksonwu.xyz/examples.md - **263 / 266 synthetic positive checks detected.** 3 missed, all for one rule. Controls quiet: 240/242 corrected, 237/252 lookalike. 7 incomplete. 93 rules. https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus - **258 / 300 real contract roots fully analyzed.** Baseline analysis. 237/300 complete for every selected rule; 27 compiler-rejected roots stay in the denominator; 0 process failures. Aggregate only. https://nightshade.dicksonwu.xyz/evaluation.md#real-contracts Nightshade 0.1.1, proof run on 2026-10-24. None of these numbers is a precision or recall estimate. Details: https://nightshade.dicksonwu.xyz/evaluation.md ## Machine-readable docs Every page has a Markdown twin. Index: https://nightshade.dicksonwu.xyz/llms.txt. Whole site: https://nightshade.dicksonwu.xyz/llms-full.txt. Rule catalog: https://nightshade.dicksonwu.xyz/rules.json. ## Source and license Nightshade is open source under Apache-2.0: https://github.com/DicksonWu654/nightshade. Release: https://github.com/DicksonWu654/nightshade/releases/tag/v0.1.1. I built it with a lot of help from AI coding agents, so expect rough edges. False positives, missed patterns and rule ideas are welcome as GitHub issues; report security problems privately. ===== # Getting started > Install the Nightshade v0.1.1 release, scan the shipped example, then scan your own Compact contracts and read the result. Canonical: https://nightshade.dicksonwu.xyz/getting-started.html Release: Nightshade 0.1.1 (v0.1.1) ## Install the release The release package targets Linux x86-64/glibc with Node 22 or 24 and libstdc++ providing `GLIBCXX_3.4.31` or newer (Ubuntu 24.04 or Debian 13). You also need curl and npm. Use an empty directory so installation stays separate from your project. ```sh curl -fL https://github.com/DicksonWu654/nightshade/releases/download/v0.1.1/nightshade-compact-0.1.1.tgz -o nightshade-compact-0.1.1.tgz npm install --prefix ./.nightshade --no-audit --no-fund ./nightshade-compact-0.1.1.tgz ./.nightshade/node_modules/.bin/nightshade ./.nightshade/node_modules/nightshade-compact/examples/review/contract.compact --fail-on high ``` This scans the positive example shipped in the tarball. It prints a medium `ledger-bound-preimage-publication` finding and exits successfully because the failure threshold is high. Installation downloads dependencies; normal scans do not need network access. Scan the corrected example next: ```sh ./.nightshade/node_modules/.bin/nightshade ./.nightshade/node_modules/nightshade-compact/examples/review/corrected.compact ``` Expect no findings and complete analysis. That is a control for this rule, not a security certification. ## Scan your application Replace the example path with your contract or project directory. These commands assume you are still in the install directory: ```sh ./.nightshade/node_modules/.bin/nightshade /path/to/contracts --compiler-version 0.34.0 --fail-on medium ./.nightshade/node_modules/.bin/nightshade /path/to/contracts --compiler-version 0.34.0 --json ./.nightshade/node_modules/.bin/nightshade /path/to/contracts --compiler-version 0.34.0 --sarif > report.sarif ``` Choose the compiler profile your application actually uses. Normal scans neither run a compiler nor establish compiler acceptance. Install application imports locally first. Add dependency directories with `--compact-path`; multiple directories use the platform path delimiter. `COMPACT_PATH` is also supported. Directory scans discover application roots and skip dependency, generated and cache directories. Imported code is still analyzed. A directory containing only libraries is incomplete; choose a root exporting the circuits you want to review. Use configured roots for a stable application selection. ## Read the result | Exit code | Default coverage policy | | --- | --- | | 0 | Complete analysis; no unsuppressed new finding meets the threshold | | 1 | Complete analysis; a finding meets the threshold | | 2 | Incomplete or invalid analysis, configuration error or worker failure | Check diagnostics, `status`, `coverage.baselineStatus` and `coverage.rules`. A quiet result with missing coverage needs investigation. `--fail-on none` does not clear incomplete analysis. An explicit rule-warning policy can permit only rule-scoped gaps while preserving incomplete status; see [configuration](https://nightshade.dicksonwu.xyz/configuration.md). ## Other installation routes For a source checkout, the prerequisites are Linux x86-64/glibc, Node 22 or 24, npm, Git, Python, make and a C/C++ compiler. From that checkout: ```sh npm ci npm run build npm run demo ``` The demo verifies the shipped positive and corrected control. Installation and build download pinned dependencies and build tools. For macOS, use the Linux Docker image from a source checkout: ```sh docker build --platform linux/amd64 -t nightshade:local . docker run --platform linux/amd64 --rm --network none -v "$PWD:/project:ro" nightshade:local examples/review/contract.compact ``` The positive example returns a finding status. Mount application imports alongside sources. Other native targets need separate build qualification. [Release](https://github.com/DicksonWu654/nightshade/releases/tag/v0.1.1) | [Full user guide](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/user-guide.md) | [Compiler profiles](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/compiler-onboarding.md#supported-profiles) | [CI setup](https://nightshade.dicksonwu.xyz/github-action.md) ===== # Examples > Ten synthetic Nightshade findings with the flagged Compact code, the exact CLI output, a corrected version that stays quiet and a lookalike. Canonical: https://nightshade.dicksonwu.xyz/examples.html Release: Nightshade 0.1.1 (v0.1.1) Ten synthetic examples, each for a different rule. Every example shows the flagged code, the exact output from the released 0.1.1 CLI, a corrected version that the rule no longer flags and, for nine of them, a lookalike that resembles the problem but stays quiet. Every file passed Compact 0.34.0 compiler validation in the same run. 1. Private authentication preimage reaches the public ledger (`ledger-bound-preimage-publication`, medium) 2. A public key comparison does not prove ownership (`spoofable-authorization`, high) 3. The signature verification result is discarded (`ignored-validation-result`, medium) 4. Caller time needs a chain-time bound (`freshness-bound-caller-time`, medium) 5. Initialization can run repeatedly (`re-initialization`, low) 6. Two shielded mints reuse the same descriptor (`duplicate-shielded-mint`, medium) 7. The Merkle membership result is ignored (`merkle-membership-not-enforced`, medium) 8. An unchecked witness value becomes public state (`unconstrained-witness-to-state`, medium) 9. A freshness check never consumes the nullifier (`nullifier-check-without-insert`, medium) 10. A private commitment uses fixed randomness (`predictable-commitment-randomness`, medium) ## Private authentication preimage reaches the public ledger Synthetic example 1 of 10. Rule: [ledger-bound-preimage-publication](https://nightshade.dicksonwu.xyz/rules/ledger-bound-preimage-publication.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. A secret checked against a stored hash is then written directly to public state. ### Flagged vulnerable.compact, line 12 flagged: ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Field; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(secret); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Ledger-bound private preimage is published [ledger-bound-preimage-publication] vulnerable.compact:12:3 12 | published = disclose(secret); | ^ Private value from ownerSecret reaches ledger-write published without a hiding transformation. A hash of this value is asserted equal to ledger ownerHash on the same potential successful path. Ledger operation data is public. If an untrusted observer obtains a reusable authentication secret through this boundary, secrecy is lost. An intentional reveal protocol may permit this flow. Source: vulnerable.compact:10:18 Constraint: vulnerable.compact:11:3 Call path: update Remediation: Keep reusable authentication preimages private; publish a suitable commitment or non-secret result. If this is intentional reveal, confirm that the revealed value grants no remaining authority and document that policy. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Publish the hash instead of the secret. ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Bytes<32>; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(persistentHash(secret)); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A witness value is published, but it is never checked against a ledger hash, so it is not an authentication preimage. ```compact pragma language_version >= 0.26.0; export ledger published: Field; witness publicReading(): Field; export circuit record(): [] { published = disclose(publicReading()); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "ledger-bound-preimage-publication" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/direct.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/hash-only.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/ordinary-disclosure.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## A public key comparison does not prove ownership Synthetic example 2 of 10. Rule: [spoofable-authorization](https://nightshade.dicksonwu.xyz/rules/spoofable-authorization.md). Severity: high. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. Comparing a caller-supplied public identity with the stored owner does not prove possession of its secret. ### Flagged vulnerable.compact, line 6 flagged: ```compact import CompactStandardLibrary; export ledger owner: ZswapCoinPublicKey; export ledger stored: Field; export circuit change(next: Field): [] { assert(ownPublicKey() == owner, "owner"); stored = disclose(next); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc HIGH — Public-key equality gates a state-changing effect [spoofable-authorization] vulnerable.compact:6:3 6 | assert(ownPublicKey() == owner, "owner"); | ^ change requires raw witness data from ownPublicKey to equal ledger owner on every modeled successful reach. The guard covers 1 effect site: ledger-write stored. Every successful history reaching these effects has only raw-witness/public-data checks; no additional modeled gate is present. Equality alone does not demonstrate possession of a secret; review the intended authentication and protocol role. Source: vulnerable.compact:6:10 Constraint: vulnerable.compact:6:3 Call path: change Remediation: If this check is intended as authentication, enforce a suitable secret-preimage or protocol-specific proof. Review key initialization, secrecy and replay assumptions. Document and triage intentional public-data validation. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Authorize with a private key preimage checked against the stored owner hash. ```compact import CompactStandardLibrary; export ledger owner: Bytes<32>; export ledger stored: Field; witness privateKey(): Bytes<32>; export circuit change(next: Field): [] { assert(persistentHash>(privateKey()) == owner, "secret preimage"); stored = disclose(next); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A local helper named ownPublicKey returns ledger data, and a witness comparison is returned rather than enforced. ```compact export ledger owner: Bytes<32>; export ledger stored: Field; witness identity(): Bytes<32>; circuit ownPublicKey(): Bytes<32> { return owner; } export circuit publicValidation(next: Field): [] { assert(ownPublicKey() == owner, "public value, no witness"); stored = disclose(next); } export circuit onlyComparison(): Boolean { return disclose(identity() == owner); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "spoofable-authorization" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/spoofable-authorization.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/spoofable-authorization.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/spoofable-authorization-lookalike.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## The signature verification result is discarded Synthetic example 3 of 10. Rule: [ignored-validation-result](https://nightshade.dicksonwu.xyz/rules/ignored-validation-result.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. The signature verifier returns a boolean, but the state change proceeds without asserting that it is true. ### Flagged vulnerable.compact, line 23 flagged: ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Synthetic regression mutation; no upstream-project finding is claimed. pragma language_version >= 0.20; import CompactStandardLibrary; export ledger round: Counter; export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); jubjubSchnorrVerify<1>(msg, sig, pk); round.increment(1); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Signature verification outcome is discarded [ignored-validation-result] vulnerable.compact:23:3 23 | jubjubSchnorrVerify<1>(msg, sig, pk); | ^ The Boolean outcome of the canonical jubjubSchnorrVerify is discarded. The call may impose internal constraints, but its signature-validity result does not constrain this caller through this use. Remediation: Assert the verification result, or reject the false branch before the transaction can succeed. Preserve intentional Boolean checker APIs; suppress intentional verifier-only tests with a reason. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Assert the verifier's result. ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Synthetic regression mutation; no upstream-project finding is claimed. pragma language_version >= 0.20; import CompactStandardLibrary; export ledger round: Counter; export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); assert(jubjubSchnorrVerify<1>(msg, sig, pk), "signature"); round.increment(1); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike The circuit asserts a local Boolean check and never calls a signature verifier. ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // transition function changing public state export circuit increment(): [] { round.increment(1); } circuit ownedCheck(): Boolean { return true; } export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); assert(ownedCheck(), "owned public validation"); round.increment(1); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "ignored-validation-result" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/counter-ignored-validation-positive.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/counter-ignored-validation-corrected.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/counter-ignored-validation-lookalike.compact. Unrelated baseline circuits and ledgers removed; original licence header retained where present. Paths in the output are shortened to the example folder. ## Caller time needs a chain-time bound Synthetic example 4 of 10. Rule: [freshness-bound-caller-time](https://nightshade.dicksonwu.xyz/rules/freshness-bound-caller-time.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. The circuit accepts a caller-supplied time window without bounding it against chain time. ### Flagged vulnerable.compact, line 14 flagged: ```compact pragma language_version >= 0.23; import CompactStandardLibrary; export ledger startedAt: Uint<64>; export ledger authenticated: Boolean; constructor() { startedAt = 0; authenticated = false; } export circuit authenticate(expectedTimeWindow: Uint<64>): [] { assert(disclose(expectedTimeWindow >= startedAt), "window"); startedAt = disclose(expectedTimeWindow); authenticated = true; } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Caller time is not bound to protocol time [freshness-bound-caller-time] vulnerable.compact:14:3 14 | startedAt = disclose(expectedTimeWindow); | ^ authenticate accepts caller-supplied expectedTimeWindow and uses it in a state-changing or public effect without an asserted canonical block-time bound. A delayed, future-dated or stale proof may remain valid outside the intended freshness window. This source/effect review does not establish transaction ordering or exploitability. Source: vulnerable.compact:12:29 Call path: authenticate Remediation: Compare the caller value with block time using canonical blockTimeGte/blockTimeGt and blockTimeLte/blockTimeLt checks, or derive the deadline solely from a kernel-bound timestamp. Keep the bound on the same successful path as the state-changing effect. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Bound the caller's time with blockTimeGte before using it. ```compact pragma language_version >= 0.23; import CompactStandardLibrary; export ledger startedAt: Uint<64>; export ledger authenticated: Boolean; constructor() { startedAt = 0; authenticated = false; } export circuit authenticate(expectedTimeWindow: Uint<64>): [] { assert(blockTimeGte(disclose(expectedTimeWindow)), "future window"); assert(disclose(expectedTimeWindow >= startedAt), "window"); startedAt = disclose(expectedTimeWindow); authenticated = true; } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A caller-supplied amount is compared with a ledger minimum; it is not a time value. ```compact pragma language_version >= 0.23; import CompactStandardLibrary; export ledger minimum: Uint<64>; export ledger accepted: Boolean; constructor() { minimum = 1; accepted = false; } export circuit accept(amount: Uint<64>): [] { assert(disclose(amount >= minimum), "amount"); accepted = true; } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "freshness-bound-caller-time" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/drafts/rule-gaps-20261016/freshness-positive.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/drafts/rule-gaps-20261016/freshness-corrected.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/drafts/rule-gaps-20261016/freshness-lookalike.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## Initialization can run repeatedly Synthetic example 5 of 10. Rule: [re-initialization](https://nightshade.dicksonwu.xyz/rules/re-initialization.md). Severity: low. Selection: Opt-in. Compiler profile: compact-0.34.0-zkir2. An exported initializer can overwrite state again because it has no one-time guard. ### Flagged vulnerable.compact, line 3 flagged: ```compact import CompactStandardLibrary; export ledger payload: Field; export circuit initialize(value: Field): [] { payload = disclose(value); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc LOW — Initializer has a modeled state-changing second invocation [re-initialization] vulnerable.compact:3:1 3 | export circuit initialize(value: Field): [] { payload = disclose(value); } | ^ initialize has two consecutive modeled successful invocations from constructor/default storage, with fresh inputs and a potentially different surviving value in payload after the second invocation. Review whether this entry is intended to run only once; its name alone does not establish that requirement. Call path: initialize Remediation: If initialization must run once, require the pre-initialized state and preserve its transition on every successful invocation. Review intentional reconfiguration separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Guard the initializer with a one-time flag. ```compact import CompactStandardLibrary; ledger done: Boolean; export ledger payload: Field; export circuit initialize(value: Field): [] { assert(!done, "already initialized"); done = true; payload = disclose(value); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A circuit that is meant to be callable more than once and leaves no different state on a second call. ```compact import CompactStandardLibrary; export ledger ready: Boolean; // Intentionally callable more than once, with no surviving second-call change. export circuit initialize(): [] { ready = true; } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "re-initialization" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/re-initialization.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/re-initialization.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/re-initialization-lookalike.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## Two shielded mints reuse the same descriptor Synthetic example 6 of 10. Rule: [duplicate-shielded-mint](https://nightshade.dicksonwu.xyz/rules/duplicate-shielded-mint.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. Two mint calls use identical token, amount, nonce and recipient inputs on the same path. ### Flagged vulnerable.compact, line 7 flagged: ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Duplicate shielded mint commitment [duplicate-shielded-mint] vulnerable.compact:7:3 7 | mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); | ^ rewardTwice invokes mintShieldedToken twice with provably identical token domain, amount, nonce and active recipient on one modeled successful history. The pinned library derives the same coin commitment in this contract context; duplicate commitments are rejected by the ledger. This is a transaction availability defect, not proof of token theft or a generic commitment-opening vulnerability. Source: vulnerable.compact:6:3 Call path: rewardTwice → mintShieldedToken Remediation: Use a distinct nonce for each minted output, for example evolveNonce with a distinct index. Review freshness across separate transactions independently. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Give the second mint a distinct nonce. ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(1,nonce)),to); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike Two mints share a nonce but use different amounts, so the descriptors differ. ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),2,disclose(evolveNonce(0,nonce)),to); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "duplicate-shielded-mint" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-duplicate-mint-positive.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-duplicate-mint-corrected.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-duplicate-mint-lookalike.compact (trimmed here). Unrelated baseline circuits and ledgers removed; original licence header retained where present. Paths in the output are shortened to the example folder. ## The Merkle membership result is ignored Synthetic example 7 of 10. Rule: [merkle-membership-not-enforced](https://nightshade.dicksonwu.xyz/rules/merkle-membership-not-enforced.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. Computing and checking a Merkle root does not enforce membership when the boolean result is discarded. ### Flagged vulnerable.compact, line 7 flagged: ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); tree.checkRoot(disclose(digest)); accepted = disclose(proof.leaf); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Proof-related effect lacks enforced trusted-root membership [merkle-membership-not-enforced] vulnerable.compact:7:18 7 | const digest = merkleTreePathRoot<2,Field>(proof); | ^ accept has a modeled successful history where proof-related data influences accepted, without a required check of that digest against definite preexisting ledger root data. Computing or ignoring a membership result does not enforce it. Review whether this effect requires membership; public deposits and root-management flows may be intentional. Source: vulnerable.compact:7:18 Call path: accept → merkleTreePathRoot Remediation: If membership is required, constrain successful execution with the exact digest's ledger-tree checkRoot result or equality with the intended trusted root. Preserve valid alternate checks and intentional public behavior. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Assert the result of checkRoot. ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); assert(tree.checkRoot(disclose(digest)), "member"); accepted = disclose(proof.leaf); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A local function named merkleTreePathRoot returns a default digest and no ledger tree is involved. ```compact import { MerkleTreePath, MerkleTreeDigest } from CompactStandardLibrary; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; circuit merkleTreePathRoot(proof: MerkleTreePath<2,Field>): MerkleTreeDigest { return default; } export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot(proof); accepted = disclose(proof.leaf); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "merkle-membership-not-enforced" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/merkle-membership-not-enforced.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/merkle-membership-not-enforced.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/merkle-membership-not-enforced-lookalike.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## An unchecked witness value becomes public state Synthetic example 8 of 10. Rule: [unconstrained-witness-to-state](https://nightshade.dicksonwu.xyz/rules/unconstrained-witness-to-state.md). Severity: medium. Selection: Opt-in. Compiler profile: compact-0.34.0-zkir2. A witness chooses the allocation written to the ledger without a preceding bound on that value. ### Flagged vulnerable.compact, line 7 flagged: ```compact // Owned synthetic witness-to-state regression. import CompactStandardLibrary; export ledger allocation: Uint<64>; witness rewardAmount(): Uint<64>; export circuit allocate(): [] { const value=rewardAmount(); allocation=disclose(value); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Raw witness value reaches ledger state without a value-specific assertion [unconstrained-witness-to-state] vulnerable.compact:7:15 7 | const value=rewardAmount(); | ^ allocate writes raw output of rewardAmount into allocation on a modeled successful history without an assertion depending on that witness leaf. Disclosure permits publication; it does not validate the value. An unrelated caller guard or a witness attestation about the value supplies no circuit validation. Public registration and prover-chosen metadata can be intentional; review the required application relation. Source: vulnerable.compact:7:15 Call path: allocate Remediation: If this field must represent an independently established fact, enforce the required relationship in the circuit using the exact supplied value. Document intentionally prover-chosen data. Review authorization and the adequacy of the check separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Assert a bound on the witness value before writing it. ```compact // Owned synthetic witness-to-state regression. import CompactStandardLibrary; export ledger allocation: Uint<64>; witness rewardAmount(): Uint<64>; export circuit allocate(): [] { const value=rewardAmount(); assert(value<=100,"reward allocation"); allocation=disclose(value); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike The value written to the ledger comes from a circuit argument, not a witness. ```compact // Owned synthetic witness-to-state regression. import CompactStandardLibrary; export ledger allocation: Uint<64>; export circuit allocate(value: Uint<64>): [] { allocation=disclose(value); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "unconstrained-witness-to-state" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-witness-state-positive.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-witness-state-corrected.compact (trimmed here), https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/known-bugs/sdk-witness-state-lookalike.compact (trimmed here). Unrelated baseline circuits and ledgers removed; original licence header retained where present. Paths in the output are shortened to the example folder. ## A freshness check never consumes the nullifier Synthetic example 9 of 10. Rule: [nullifier-check-without-insert](https://nightshade.dicksonwu.xyz/rules/nullifier-check-without-insert.md). Severity: medium. Selection: Opt-in. Compiler profile: compact-0.34.0-zkir2. The circuit checks that an identifier is unused but never inserts it into the used set. ### Flagged vulnerable.compact, line 7 flagged: ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); accepted = disclose(id); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Required absence lacks a surviving matching insertion [nullifier-check-without-insert] vulnerable.compact:7:11 7 | assert(!used.member(disclose(id)), "fresh"); | ^ accept has a modeled successful state-changing history requiring absence from used, without a definite surviving insertion of that exact value/key into the same collection. Review whether this check is intended to consume a one-use identifier. Source: vulnerable.compact:7:11 Call path: accept Remediation: If this is a one-use identifier, insert the checked value/key into the same persistent collection on every successful history and retain it through transaction completion. Review intentional absence validation separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Insert the identifier into the used set. ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); used.insert(disclose(id)); accepted = disclose(id); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Lookalike A local member function checks a value without any ledger set. ```compact import CompactStandardLibrary; export ledger accepted: Field; witness token(): Field; circuit member(id: Field): Boolean { return id == (0 as Field); } export circuit accept(): [] { const id = token(); assert(!member(id), "nonzero"); accepted = disclose(id); } ``` Output (exit code 0): ```text $ nightshade lookalike.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "nullifier-check-without-insert" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/nullifier-check-without-insert.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/nullifier-check-without-insert.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/nullifier-check-without-insert-lookalike.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## A private commitment uses fixed randomness Synthetic example 10 of 10. Rule: [predictable-commitment-randomness](https://nightshade.dicksonwu.xyz/rules/predictable-commitment-randomness.md). Severity: medium. Selection: Audit default. Compiler profile: compact-0.34.0-zkir2. Publishing a commitment with fixed randomness can expose a small private input domain to guessing. ### Flagged vulnerable.compact, line 6 flagged: ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; export circuit publish(): [] { published = persistentCommit(secret(), pad(32, "")); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Public commitment uses predictable randomness [predictable-commitment-randomness] vulnerable.compact:6:3 6 | published = persistentCommit(secret(), pad(32, "")); | ^ persistentCommit commits private-derived input using statically known randomness, and its result influences ledger-write published. This removes the protection supplied by secret, unpredictable commitment randomness; low-entropy inputs can remain guessable. Intentional deterministic commitments require review. Source: vulnerable.compact:6:15 Call path: publish Remediation: Use independently generated, sufficiently entropic private randomness appropriate to the primitive and protocol. Do not replace intentional deterministic protocol commitments without reviewing compatibility. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` ### Corrected Take commitment randomness from a witness instead of a constant. ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; witness randomness(): Bytes<32>; export circuit publish(): [] { published = persistentCommit(secret(), randomness()); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Configuration (config.json): ```json { "version": 1, "compilerVersion": "0.34.0", "zkirVersion": 2, "detectors": [ "predictable-commitment-randomness" ] } ``` Source fixtures at v0.1.1: https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/vulnerable/predictable-randomness.compact, https://github.com/DicksonWu654/nightshade/blob/v0.1.1/tests/corpus/safe/predictable-randomness.compact. Original compact fixture retained. Paths in the output are shortened to the example folder. ## How these were produced [Download the proof pack](https://nightshade.dicksonwu.xyz/downloads/nightshade-proof-0.1.1.tar.gz) (`nightshade-proof-0.1.1.tar.gz`, 1.7 MB, 4692 files). SHA-256: `9d95e631dc318006610882911c0d58b7c25fa7754c39b49205c309d2e2e57b3b` It holds the synthetic input snapshot, every raw scan output with its recorded command and exit code, the per-scan configs, these ten examples, the report and the scripts that produced and check them. Local paths in it are replaced with placeholders such as `` and ``, the release tarball is left out (it is the v0.1.1 release asset) and real-contract records keep only the aggregate numbers on the [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md) page. `PUBLIC-PACK.md` inside lists every change. Each example is a synthetic contract written for the Nightshade test corpus. Some are deliberate mutations of upstream teaching examples. None of them is a finding about a real project. Each scan selects only the named rule through the example's `config.json` and uses the compiler profile `compact-0.34.0-zkir2`. The `--compiler` flag adds compiler validation (`--skip-zk` compilation with Compact 0.34.0). Normal scans do not need a compiler. Some of these rules are opt-in; the configuration selects them explicitly. Outputs are copied from the proof run. The first line of each output shows the command as you would type it: the recorded run called the installed binary by its full path under `taskset` and passed a local compiler path, which I replaced with `nightshade` and `/path/to/compactc`. In the output itself I shortened absolute file paths to paths relative to the example folder. Long lines wrap on screen. Nothing else is changed. Each example links its source fixture in the repository at v0.1.1; where the showcase file was trimmed, the fixture is the untrimmed original. A quiet corrected or lookalike scan shows that this one rule stopped firing. It does not show that the contract is secure. For the corpus-wide results, including misses, see [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md). ===== # CI with the GitHub Action > Run Nightshade in GitHub Actions, upload SARIF to code scanning and decide what fails CI. Canonical: https://nightshade.dicksonwu.xyz/github-action.html Release: Nightshade 0.1.1 (v0.1.1) The composite Action builds Nightshade from its pinned source, scans your workspace, uploads SARIF and preserves the scan exit status. It also uploads reports containing incomplete results when a report is available. ## Add a workflow Save this as `.github/workflows/nightshade.yml`: ```yaml name: Compact analysis on: [push, pull_request] permissions: contents: read security-events: write jobs: nightshade: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: DicksonWu654/nightshade@v0.1.1 with: path: contracts fail-on: medium category: compact-contracts ``` Change `contracts` to your source directory. Add your project's dependency installation before the Nightshade step so Compact imports resolve locally. Pin the Nightshade Action to a reviewed commit if you need an immutable dependency. Use a runner with a C/C++ toolchain. The Action builds the native parser on clean runners; its npm download cache does not reuse compiled native objects across workflows. ## Inputs and outputs | Input | Purpose | | --- | --- | | `path` | Contract file or project directory, relative to the workspace; defaults to `.` | | `config` | Optional JSON configuration, relative to the workspace | | `compiler-version` | Optional exact compiler profile; otherwise selected from source pragmas | | `fail-on` | Finding threshold: `info`, `low`, `medium`, `high`, `critical` or `none`; defaults to `info` | | `category` | SARIF category; use a distinct value for each application | Outputs are `exit-code` and `sarif`, the local report path on the runner. Configuration can set rule selection, imports and policies. ## Decide what fails CI With the default coverage policy, exit 0 means analysis completed and no unsuppressed new finding meets the threshold. Exit 1 means a finding meets it. Exit 2 means incomplete or invalid analysis, configuration error or worker failure. `fail-on: none` does not clear incomplete analysis. An explicit `ruleIncomplete: warn` configuration allows rule-only gaps to warn when baseline semantics are complete. Reports still say incomplete and retain diagnostics. Baseline, input, configuration and worker failures still fail. Read [configuration and suppressions](https://nightshade.dicksonwu.xyz/configuration.md) before changing this policy. SARIF upload requires GitHub code-scanning availability and the shown token permissions. Repository and event restrictions can still prevent upload. Local SARIF validation does not establish hosted access. Hosted uploads have not been established by the documented local checks. [Action source](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/action.yml) | [Full Action guide](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/user-guide.md#github-action) | [Configuration reference](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md) ===== # Rules > All 96 Nightshade rules for Compact, with severity, confidence, selection mode and a page for each rule. Canonical: https://nightshade.dicksonwu.xyz/rules.html Release: Nightshade 0.1.1 (v0.1.1) Rules are grouped by selection category, then by topic for other opt-ins. Each line gives severity, selection and a description, with a link to its documentation at v0.1.1. All built-in rules are experimental. Severity is review priority, not a probability or a confirmed impact. Intentional behavior can match. Read each rule's evidence, benign matches and limits. The implicit `audit` profile selects ordinary audit rules and dormant policy rules. `--profile hygiene` adds source hygiene. `--detectors ID,ID` replaces profile selection with an exact nonempty set. Policy rules need matching application intent even when selected. Topic headings are not CLI selection shortcuts. Machine-readable catalog: https://nightshade.dicksonwu.xyz/rules.json ## Audit-default ordinary rules 24 rules. Run on every ordinary scan. - [caller-supplied-deadline](https://nightshade.dicksonwu.xyz/rules/caller-supplied-deadline.md): Caller-supplied time satisfies a ledger-derived delay without a chain-time upper bound. Severity medium; Audit default; confidence medium. - [circuit-cost](https://nightshade.dicksonwu.xyz/rules/circuit-cost.md): Expanded source-operation estimate exceeds the review threshold; this is not a proof-row estimate. Severity info; Audit default; confidence high. - [discarded-comparison](https://nightshade.dicksonwu.xyz/rules/discarded-comparison.md): A comparison not reduced to a source constant is discarded or kept only by unused immutable aliases. Severity low; Audit default; confidence high. - [discarded-shielded-send-result](https://nightshade.dicksonwu.xyz/rules/discarded-shielded-send-result.md): Canonical shielded send or mint metadata is discarded or retained only by unused immutable aliases. Severity info; Audit default; confidence varies. - [duplicate-shielded-mint](https://nightshade.dicksonwu.xyz/rules/duplicate-shielded-mint.md): Identical canonical shielded mint inputs produce a duplicate coin commitment in one transaction. Severity medium; Audit default; confidence varies. - [duplicated-branch-tail](https://nightshade.dicksonwu.xyz/rules/duplicated-branch-tail.md): Terminating branch repeats its immediate following expression and return tail. Severity info; Audit default; confidence high. - [either-payload-mismatch](https://nightshade.dicksonwu.xyz/rules/either-payload-mismatch.md): A native Either's known inactive arm reaches an output, state effect or successful effect gate. Severity info; Audit default; confidence high. - [field-recomposition-range-review](https://nightshade.dicksonwu.xyz/rules/field-recomposition-range-review.md): Enforced Field recomposition retains quotient/remainder envelopes beyond the modulus. Severity info; Audit default; confidence high. - [freshness-bound-caller-time](https://nightshade.dicksonwu.xyz/rules/freshness-bound-caller-time.md): Caller-supplied time reaches a security-sensitive effect without a canonical block-time freshness bound. Severity medium; Audit default; confidence medium. - [identity-signature-key](https://nightshade.dicksonwu.xyz/rules/identity-signature-key.md): A successful history passes a known identity point to the pinned Schnorr verifier. Severity medium; Audit default; confidence high. - [ignored-validation-result](https://nightshade.dicksonwu.xyz/rules/ignored-validation-result.md): A canonical signature verifier's Boolean outcome is discarded or retained only by unused local aliases. Severity medium; Audit default; confidence high. - [impossible-assertion](https://nightshade.dicksonwu.xyz/rules/impossible-assertion.md): A nonliteral assertion fails on every reaching path, or an entry has no successful path. Severity medium; Audit default; confidence high. - [ledger-bound-preimage-publication](https://nightshade.dicksonwu.xyz/rules/ledger-bound-preimage-publication.md): A private preimage checked against a ledger hash is also published on a potential successful path. Severity medium; Audit default; confidence medium. - [low-entropy-hash-disclosure](https://nightshade.dicksonwu.xyz/rules/low-entropy-hash-disclosure.md): A published direct hash has one private input drawn from a small declared domain. Severity medium; Audit default; confidence high. - [merkle-leaf-binding-review](https://nightshade.dicksonwu.xyz/rules/merkle-leaf-binding-review.md): Checked Merkle path leaves lack binding to supplied lookup inputs or exact Field hash write candidates. Severity info; Audit default; confidence varies. - [merkle-membership-not-enforced](https://nightshade.dicksonwu.xyz/rules/merkle-membership-not-enforced.md): Proof-related state changes lack an enforced relationship between the exact digest and trusted ledger roots. Severity medium; Audit default; confidence low. - [missing-role-bootstrap](https://nightshade.dicksonwu.xyz/rules/missing-role-bootstrap.md): An authenticated ShieldedAccessControl instance initializes but has no role-seeding route. Severity low; Audit default; confidence varies. - [predictable-commitment-randomness](https://nightshade.dicksonwu.xyz/rules/predictable-commitment-randomness.md): A published private-derived commitment uses statically known randomness. Severity medium; Audit default; confidence high. - [public-key-membership-authorization](https://nightshade.dicksonwu.xyz/rules/public-key-membership-authorization.md): A raw native ownPublicKey selects a required member of preexisting public ledger storage before successful state-changing effects. Severity high; Audit default; confidence high. - [publicly-derivable-encryption-secret](https://nightshade.dicksonwu.xyz/rules/publicly-derivable-encryption-secret.md): A published digest determines the scalar of a registered curve point through resolved native calls. Severity high; Audit default; confidence varies. - [redundant-boolean-branch](https://nightshade.dicksonwu.xyz/rules/redundant-boolean-branch.md): Both branch arms only return opposite Boolean literals. Severity info; Audit default; confidence high. - [redundant-self-shielded-receive](https://nightshade.dicksonwu.xyz/rules/redundant-self-shielded-receive.md): Exact self-addressed canonical returned coin is subsequently passed to receiveShielded. Severity info; Audit default; confidence high. - [spoofable-authorization](https://nightshade.dicksonwu.xyz/rules/spoofable-authorization.md): A raw witness equality with public data is required for a state-changing effect; review the intended authentication. Severity low / high / critical; Audit default; confidence varies. - [zero-amount-set-consumption-review](https://nightshade.dicksonwu.xyz/rules/zero-amount-set-consumption-review.md): Review exact surviving Set absence consumption before a zero-inclusive canonical unshielded payout. Severity info; Audit default; confidence varies. ## Additional hygiene rules 7 rules. Added by --profile hygiene. - [always-true-assertion](https://nightshade.dicksonwu.xyz/rules/always-true-assertion.md): Assertion is already true on every analyzed reach before enforcing it. Severity info; Hygiene only; confidence high. - [constant-condition](https://nightshade.dicksonwu.xyz/rules/constant-condition.md): Branch condition reduces to a typed scalar source constant. Severity info; Hygiene only; confidence high. - [dead-code](https://nightshade.dicksonwu.xyz/rules/dead-code.md): Statement, branch or loop is excluded by source control flow. Severity info; Hygiene only; confidence high. - [shadowing](https://nightshade.dicksonwu.xyz/rules/shadowing.md): Parameter or local binding hides an outer declaration. Severity info; Hygiene only; confidence high. - [time-dependence](https://nightshade.dicksonwu.xyz/rules/time-dependence.md): A successful circuit uses a protocol block-time comparison. Severity info; Hygiene only; confidence high. - [unnecessary-disclose](https://nightshade.dicksonwu.xyz/rules/unnecessary-disclose.md): Disclosure operand is already public in the source context. Severity info; Hygiene only; confidence high. - [unused-declaration](https://nightshade.dicksonwu.xyz/rules/unused-declaration.md): Ledger, witness or private circuit has no reference in the compilation unit. Severity info; Hygiene only; confidence high. ## Policy-dependent rules 13 rules. Need application intent declared in policies. - [checkpoint-splits-atomic-update](https://nightshade.dicksonwu.xyz/rules/checkpoint-splits-atomic-update.md): A checkpoint splits a declared ordinary Cell co-update across atomic units. Severity low; Opt-in + policy; confidence high. - [circuit-work-budget](https://nightshade.dicksonwu.xyz/rules/circuit-work-budget.md): Expanded source-operation estimate exceeds an explicit circuit work budget. Severity low; Audit; needs policy; confidence high. - [current-root-policy-mismatch](https://nightshade.dicksonwu.xyz/rules/current-root-policy-mismatch.md): An explicitly selected membership guard lacks current-root evidence at enforcement time. Severity medium; Opt-in + policy; confidence medium. - [declared-secret-publication](https://nightshade.dicksonwu.xyz/rules/declared-secret-publication.md): Policy-declared secret information reaches a public sink through an unapproved transformation. Severity high; Audit; needs policy; confidence medium. - [forbidden-state-transition](https://nightshade.dicksonwu.xyz/rules/forbidden-state-transition.md): A scalar state write may cross a transition explicitly forbidden by policy. Severity medium; Audit; needs policy; confidence medium. - [openzeppelin-preconditions](https://nightshade.dicksonwu.xyz/rules/openzeppelin-preconditions.md): Opt-in documented preconditions of authenticated OpenZeppelin Compact modules. Severity medium; Configured builtins; confidence high. - [operation-intent-policy](https://nightshade.dicksonwu.xyz/rules/operation-intent-policy.md): A protected Cell mutation does not satisfy its declared complete operation-intent statement. Severity info; Opt-in + policy; confidence high. - [source-claim-map-getter-review](https://nightshade.dicksonwu.xyz/rules/source-claim-map-getter-review.md): An explicitly documented configured Map getter returns only default without reading the selected Map. Severity info; Opt-in + policy; confidence varies. - [source-claim-shielded-issuance-review](https://nightshade.dicksonwu.xyz/rules/source-claim-shielded-issuance-review.md): Review an explicit adjacent source claim paired with shielded issuance to a user key. Severity info; Opt-in + policy; confidence varies. - [stale-nft-metadata](https://nightshade.dicksonwu.xyz/rules/stale-nft-metadata.md): Policy-selected current NFT metadata retains an old auxiliary payload across same-history burn/remint. Severity low; Opt-in + policy; confidence varies. - [unguarded-sensitive-state-write](https://nightshade.dicksonwu.xyz/rules/unguarded-sensitive-state-write.md): A successful path writes policy-protected state without the configured preceding guard. Severity high; Audit; needs policy; confidence medium. - [unsupported-contract-owner](https://nightshade.dicksonwu.xyz/rules/unsupported-contract-owner.md): A declared callable pinned Ownable instance finishes with a contract-address owner rejected by its guard. Severity medium; Opt-in + policy; confidence high. - [zero-amount-initial-membership](https://nightshade.dicksonwu.xyz/rules/zero-amount-initial-membership.md): Under a declared zero-amount policy, every modeled successful invocation requires the same Map entry to have been present initially. Severity low; Opt-in + policy; confidence low. ## Other active opt-ins 52 rules. Select them explicitly with --detectors or the detectors list. ### Time and freshness - [caller-supplied-time-review](https://nightshade.dicksonwu.xyz/rules/caller-supplied-time-review.md): Review an effect-bearing caller value checked against a ledger bound without a same-branch exact clock constraint; time intent unknown. Severity medium; Opt-in; confidence medium. - [shielded-coin-runtime-width](https://nightshade.dicksonwu.xyz/rules/shielded-coin-runtime-width.md): A definite native shielded output exceeds the expressly assumed runtime coin encoding range. Severity low; Opt-in; confidence low. ### Authorization, identity and membership - [caller-key-zero-entry-review](https://nightshade.dicksonwu.xyz/rules/caller-key-zero-entry-review.md): Review a surviving zero numeric Map insertion at a direct caller key without required initial same-key membership. Severity info; Opt-in; confidence high. - [closed-membership-capacity-review](https://nightshade.dicksonwu.xyz/rules/closed-membership-capacity-review.md): A represented constructor history contradicts distinct Set memberships under a complete source closure without subsequent writers. Severity info; Opt-in; confidence varies. - [configured-membership-capacity-review](https://nightshade.dicksonwu.xyz/rules/configured-membership-capacity-review.md): Immediate post-constructor collection capacity contradicts required distinct memberships. Severity info; Opt-in; confidence high. - [enrolled-signature-key-review](https://nightshade.dicksonwu.xyz/rules/enrolled-signature-key-review.md): Review unknown persistent Schnorr keys without modeled identity rejection. Severity info; Opt-in; confidence varies. - [membership-identity-binding-review](https://nightshade.dicksonwu.xyz/rules/membership-identity-binding-review.md): Keyed mutation digest/key equality and required Set membership use independent witness snapshots. Severity info; Opt-in; confidence varies. - [native-key-authentication-review](https://nightshade.dicksonwu.xyz/rules/native-key-authentication-review.md): Canonical prover-supplied ownPublicKey participates in a required ledger credential check. Severity info; Opt-in; confidence high. - [quorum-signer-uniqueness-review](https://nightshade.dicksonwu.xyz/rules/quorum-signer-uniqueness-review.md): Adjacent signer inequalities omit non-adjacent pairs in a verified threshold claim vector. Severity info; Opt-in; confidence high. - [signature-key-identity-exclusion-review](https://nightshade.dicksonwu.xyz/rules/signature-key-identity-exclusion-review.md): Review unknown native signature keys without modeled exact identity exclusion. Severity info; Opt-in; confidence varies. - [split-witness-identity](https://nightshade.dicksonwu.xyz/rules/split-witness-identity.md): Ledger-bound witness digest and mutation operand use independently supplied witness snapshots without mandatory equality binding. Severity low; Opt-in; confidence high. - [stored-schnorr-key-enrollment-review](https://nightshade.dicksonwu.xyz/rules/stored-schnorr-key-enrollment-review.md): Review stored supplied Schnorr keys with enrollment and enforced canonical use lacking modeled identity rejection. Severity info; Opt-in; confidence varies. - [zero-default-getter-membership-review](https://nightshade.dicksonwu.xyz/rules/zero-default-getter-membership-review.md): Review explicit absent-to-zero getter evidence alongside an all-zero-success initial-membership Map decrement. Severity info; Opt-in; confidence high. ### Privacy and cryptographic derivations - [checked-digest-narrowing](https://nightshade.dicksonwu.xyz/rules/checked-digest-narrowing.md): A full canonical hash is range-checked by a Uint cast on its source route to a ledger write or exported return. Severity info; Opt-in; confidence high. - [conditional-hash-range](https://nightshade.dicksonwu.xyz/rules/conditional-hash-range.md): Conditional unsigned subtraction reaches a fixed-width native persistent-hash input without a qualified inactive-case range invariant. Severity low; Opt-in; confidence low. - [generic-witness-maybe-abi](https://nightshade.dicksonwu.xyz/rules/generic-witness-maybe-abi.md): Shared generic optional witness dispatch has incompatible mandatory bigint/byte-array payload guards; profile-specific compatibility review. Severity low; Opt-in; confidence low. - [public-two-component-domain-review](https://nightshade.dicksonwu.xyz/rules/public-two-component-domain-review.md): Review a public two-input native digest lacking represented self binding and component default exclusion. Severity info; Opt-in; confidence high. - [published-digest-generator-scalar-review](https://nightshade.dicksonwu.xyz/rules/published-digest-generator-scalar-review.md): Published exact digest determines a scalar used in native generator multiplication whose result survives in a ledger Cell. Severity info; Opt-in; confidence high. - [secret-binding-divergence-review](https://nightshade.dicksonwu.xyz/rules/secret-binding-divergence-review.md): Same-key ledger writers enforce different domain-qualified secret-binding declaration families. Severity info; Opt-in; confidence varies. - [transient-digest-to-ledger](https://nightshade.dicksonwu.xyz/rules/transient-digest-to-ledger.md): Terminal ledger data is constructed using an upgrade-unstable transient hash or commitment. Severity low; Opt-in; confidence low. - [unconstrained-witness-to-state](https://nightshade.dicksonwu.xyz/rules/unconstrained-witness-to-state.md): A raw witness leaf reaches surviving ledger state without a modeled assertion using that leaf. Severity medium; Opt-in; confidence varies. - [witness-derived-value-review](https://nightshade.dicksonwu.xyz/rules/witness-derived-value-review.md): Review direct witness-derived canonical-send recipients without an exact prior ledger equality binding. Severity medium; Opt-in; confidence varies. ### Token, coin and value transfers - [exported-shielded-descriptor](https://nightshade.dicksonwu.xyz/rules/exported-shielded-descriptor.md): Canonical shielded coin descriptor fields have an unchanged source route to an exported result. Severity info; Opt-in; confidence varies. - [permissionless-mint-egress](https://nightshade.dicksonwu.xyz/rules/permissionless-mint-egress.md): Permissionless mint and egress compose around a stored-value boundary without a modeled authorization predicate. Severity high; Opt-in; confidence high. - [received-coin-not-validated](https://nightshade.dicksonwu.xyz/rules/received-coin-not-validated.md): Received shielded coin lacks a recorded application constraint on color or value. Severity low; Opt-in; confidence low. - [shielded-burn-amount-width](https://nightshade.dicksonwu.xyz/rules/shielded-burn-amount-width.md): An exported amount is forwarded unchanged to a canonical shielded burn whose coin and API amount types are wider. Severity info; Opt-in; confidence high. - [shielded-contract-recipient-review](https://nightshade.dicksonwu.xyz/rules/shielded-contract-recipient-review.md): Review canonical shielded sends with a modeled non-self ContractAddress recipient arm. Severity info; Opt-in; confidence varies. - [signed-effect-input](https://nightshade.dicksonwu.xyz/rules/signed-effect-input.md): Review ordinary state or shielded input coin sources absent from enforced signature message dependencies. Severity low; Opt-in; confidence varies. - [unbounded-mint](https://nightshade.dicksonwu.xyz/rules/unbounded-mint.md): A variable mint amount has no modeled per-call cap below the native range or public ledger bound. Severity medium; Opt-in; confidence varies. - [unprotected-value-transfer](https://nightshade.dicksonwu.xyz/rules/unprotected-value-transfer.md): Successful token operations have no required application predicate constraining private caller inputs. Severity low; Opt-in; confidence low. - [unshielded-refund-endpoint-review](https://nightshade.dicksonwu.xyz/rules/unshielded-refund-endpoint-review.md): Review a complete local refund-validator endpoint producing a zero remainder send expression. Severity info; Opt-in; confidence varies. - [zero-amount-complementary-send-review](https://nightshade.dicksonwu.xyz/rules/zero-amount-complementary-send-review.md): Review exact same-color complementary sends with two zero-inclusive amount envelopes. Severity info; Opt-in; confidence varies. - [zero-amount-unguarded-map-debit-review](https://nightshade.dicksonwu.xyz/rules/zero-amount-unguarded-map-debit-review.md): Review an amount-zero successful numeric Map debit whose exact lookup has unknown prior membership. Severity info; Opt-in; confidence high. - [zero-amount-unshielded-send](https://nightshade.dicksonwu.xyz/rules/zero-amount-unshielded-send.md): Review canonical unshielded send amounts with a zero-inclusive successful-history range. Severity info; Opt-in; confidence varies. - [zero-transfer-retained-list-review](https://nightshade.dicksonwu.xyz/rules/zero-transfer-retained-list-review.md): Review zero-inclusive actual transfers paired with retained List append for the exact user recipient. Severity info; Opt-in; confidence varies. ### State and collections - [caller-supplied-ledger-equality](https://nightshade.dicksonwu.xyz/rules/caller-supplied-ledger-equality.md): An unchanged caller input must equal preexisting public ledger bytes before a state-changing effect. Severity medium; Opt-in; confidence medium. - [destructive-list-reset](https://nightshade.dicksonwu.xyz/rules/destructive-list-reset.md): Whole-list reset lacks a recognized same-revision count, empty-list or absent-slot acknowledgment. Severity low; Opt-in; confidence varies. - [inconsistent-keyed-state-guard](https://nightshade.dicksonwu.xyz/rules/inconsistent-keyed-state-guard.md): Consumer co-membership is checked on only some successful histories of a keyed insert. Severity info; Opt-in; confidence high. - [mutually-exclusive-terminal-payout](https://nightshade.dicksonwu.xyz/rules/mutually-exclusive-terminal-payout.md): Terminal payout remains reachable after a mutually exclusive one-time milestone. Severity high; Opt-in; confidence high. - [re-initialization](https://nightshade.dicksonwu.xyz/rules/re-initialization.md): Opt-in review of initializer-named entries with a state-changing second invocation. Severity low; Opt-in; confidence low. - [resettable-list-nonce](https://nightshade.dicksonwu.xyz/rules/resettable-list-nonce.md): Canonical shielded coin nonce derives solely from a selected ledger List length that another exported entry can reset. Severity low; Opt-in; confidence high. - [resettable-memo-nonce-review](https://nightshade.dicksonwu.xyz/rules/resettable-memo-nonce-review.md): Stored recipient List payload and canonical coin nonce both evolve from the same resettable selected List extent. Severity info; Opt-in; confidence high. - [shared-module-once-gate](https://nightshade.dicksonwu.xyz/rules/shared-module-once-gate.md): Distinct importing module wrappers expose one canonical false-guard then true-write Boolean gate. Severity info; Opt-in; confidence high. - [write-only-ledger](https://nightshade.dicksonwu.xyz/rules/write-only-ledger.md): Ordinary ledger Cell is explicitly written but has no Compact source read in the compilation unit. Severity info; Opt-in; confidence high. ### Source structure and validation - [default-recipient-or-owner](https://nightshade.dicksonwu.xyz/rules/default-recipient-or-owner.md): A successful value output or pinned Ownable update uses a known default active address. Severity medium; Opt-in; confidence high. - [exact-balance-threshold](https://nightshade.dicksonwu.xyz/rules/exact-balance-threshold.md): A threshold-only assertion uses the exact unshielded balance getter instead of its comparison API. Severity info; Opt-in; confidence high. - [field-arithmetic-wraparound](https://nightshade.dicksonwu.xyz/rules/field-arithmetic-wraparound.md): A directly published Field operation on preserved unsigned quantities may wrap without a proved bound. Severity medium; Opt-in; confidence varies. - [inconsistent-access-control](https://nightshade.dicksonwu.xyz/rules/inconsistent-access-control.md): An exported writer omits the caller-check convention required by a strict majority of its peers. Severity medium; Opt-in; confidence low. - [merkle-insert-without-dedupe](https://nightshade.dicksonwu.xyz/rules/merkle-insert-without-dedupe.md): Review sequential bounded Merkle insertion without exact surviving duplicate prevention. Severity info; Opt-in; confidence medium. - [nullifier-check-without-insert](https://nightshade.dicksonwu.xyz/rules/nullifier-check-without-insert.md): Required collection absence lacks a definite surviving insertion on a state-changing history. Severity medium; Opt-in; confidence low. - [publicly-derived-guard-tag](https://nightshade.dicksonwu.xyz/rules/publicly-derived-guard-tag.md): A supplied tag is required equal to a hash derived from preexisting public ledger data and caller-supplied inputs before an effect. Severity medium; Opt-in; confidence medium. - [unasserted-security-result](https://nightshade.dicksonwu.xyz/rules/unasserted-security-result.md): Review predicate outcomes discarded before effects, persisted, or returned with an effect; security intent unknown. Severity medium; Opt-in; confidence varies. ## Inspect the installed rules Using the installation from [getting started](https://nightshade.dicksonwu.xyz/getting-started.md): ```sh ./.nightshade/node_modules/.bin/nightshade detector list ./.nightshade/node_modules/.bin/nightshade detector show ledger-bound-preimage-publication ``` [Released catalog](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors.md) | [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # Configuration and suppressions > Configure Nightshade scans, select rules and failure criteria, suppress intentional matches and baseline existing findings. Canonical: https://nightshade.dicksonwu.xyz/configuration.html Release: Nightshade 0.1.1 (v0.1.1) ## Make scan settings explicit The default configuration filename is `nightshade.json`. Use an explicit file for repeatable scans: ```sh ./.nightshade/node_modules/.bin/nightshade --config ./nightshade.json --json ``` Example configuration for a project whose root is `contracts/app.compact` and whose imports are in `vendor`: ```json { "version": 1, "roots": ["contracts/app.compact"], "searchPaths": ["vendor"], "compilerVersion": "0.34.0", "failOn": "medium" } ``` Choose your actual compiler profile. Paths are relative to the configuration file. Unknown keys, wrong types and ambiguous policy selectors are errors. Configuration cannot load host detector code or a compiler executable. ## Select rules and failure criteria - `detectors` is an exact nonempty list replacing the defaults. With no override, the audit profile applies. The CLI's `--profile hygiene` adds hygiene rules. - `failOn` and `minConfidence` change failure criteria while keeping findings visible. `minSeverity` filters displayed findings. - `policies` records application intent such as secret handling and authorization. Use the exact fields documented for each rule. Selecting a policy rule alone does not supply intent. - `budgets` controls analysis work through `maxSteps`, `maxPaths` and `maxValues`. Increasing a budget can help a bounded scan finish; it does not prove coverage beyond the model. - `execution` controls worker timeout, V8 heap setting and output bounds. The heap setting is not an RSS cap or OS sandbox. Diagnostics cannot be suppressed. The default `ruleIncomplete` policy is `error`. Setting it to `warn` permits rule-scoped gaps only when baseline semantics are complete: thresholds then decide finding failures, while baseline, invalid-input and worker failures still fail. Reports retain incomplete status, per-rule gaps and all diagnostics. SARIF retains `executionSuccessful: false`. ## Suppress an intentional match Use an exact rule ID and a meaningful reason: ```compact // nightshade-disable-next-line ledger-bound-preimage-publication -- Intentional reveal after retiring this authority published = disclose(secret); ``` `nightshade-disable-line` applies to the same line. Comma-separated exact IDs are supported. The reason must contain at least eight characters. Strings and block comments are not directives. Malformed or unmatched directives for selected rules in the application root make analysis incomplete. Configuration can suppress an exact finding fingerprint with a reason. Obtain the fingerprint using the same configuration and scan settings without the suppression. An unused configured suppression is an error. JSON and SARIF retain suppressed findings and reasons; configuration reasons take precedence. ## Baseline existing findings Using the shipped example from the installation directory: ```sh baseline_dir=$(mktemp -d) ./.nightshade/node_modules/.bin/nightshade ./.nightshade/node_modules/nightshade-compact/examples/review/contract.compact --write-baseline "$baseline_dir/baseline.json" --json ./.nightshade/node_modules/.bin/nightshade ./.nightshade/node_modules/nightshade-compact/examples/review/contract.compact --baseline "$baseline_dir/baseline.json" --json ``` The creation scan returns a finding status. Replay succeeds for matching baseline fingerprints while keeping them visible as unchanged. Creation refuses overwrite and incomplete analysis. Preserve source root, compiler profile and detector settings between creation and replay; location changes can invalidate fingerprints. A baseline does not establish semantic equivalence or safety. When upgrading from v0.1.0, follow the [changelog](https://nightshade.dicksonwu.xyz/changelog.md) fingerprint migration notes before reusing a baseline or suppression. [Full configuration reference](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md) | [User guide](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/user-guide.md#baselines-and-suppressions) | [Rule catalog](https://nightshade.dicksonwu.xyz/rules.md) ===== # Evaluation > Measured results for Nightshade 0.1.1: showcase examples, the synthetic corpus and real contracts, with denominators, misses, versions and how to reproduce. Canonical: https://nightshade.dicksonwu.xyz/evaluation.html Release: Nightshade 0.1.1 (v0.1.1) This page collects the numbers I publish about Nightshade, with the denominator, version and limits next to each one. All of them come from one proof run of the released 0.1.1 CLI, installed from the release tarball on 2026-10-24. - **10 / 10 showcase findings fire.** 10 corrected versions and 9 lookalikes stay quiet. Synthetic, one rule per scan, compiler-validated. https://nightshade.dicksonwu.xyz/examples.md - **263 / 266 synthetic positive checks detected.** 3 missed, all for one rule. Controls quiet: 240/242 corrected, 237/252 lookalike. 7 incomplete. 93 rules. https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus - **258 / 300 real contract roots fully analyzed.** Baseline analysis. 237/300 complete for every selected rule; 27 compiler-rejected roots stay in the denominator; 0 process failures. Aggregate only. https://nightshade.dicksonwu.xyz/evaluation.md#real-contracts Nightshade 0.1.1, proof run on 2026-10-24. None of these numbers is a precision or recall estimate. ## Showcase examples Each of the 10 [examples](https://nightshade.dicksonwu.xyz/examples.md) selects one rule. The positive fired in 10 of 10, the corrected version was quiet in 10 of 10 and the lookalike was quiet in 9 of 9 (one example has no lookalike). Every variant passed Compact 0.34.0 compiler validation and complete analysis. Exit codes are from the same runs. | Example | Rule | Severity | Positive | Corrected | Lookalike | | --- | --- | --- | --- | --- | --- | | [Private authentication preimage reaches the public ledger](https://nightshade.dicksonwu.xyz/examples.md#ledger-bound-preimage-publication) | `ledger-bound-preimage-publication` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [A public key comparison does not prove ownership](https://nightshade.dicksonwu.xyz/examples.md#spoofable-authorization) | `spoofable-authorization` | high | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [The signature verification result is discarded](https://nightshade.dicksonwu.xyz/examples.md#ignored-validation-result) | `ignored-validation-result` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [Caller time needs a chain-time bound](https://nightshade.dicksonwu.xyz/examples.md#freshness-bound-caller-time) | `freshness-bound-caller-time` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [Initialization can run repeatedly](https://nightshade.dicksonwu.xyz/examples.md#re-initialization) | `re-initialization` | low | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [Two shielded mints reuse the same descriptor](https://nightshade.dicksonwu.xyz/examples.md#duplicate-shielded-mint) | `duplicate-shielded-mint` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [The Merkle membership result is ignored](https://nightshade.dicksonwu.xyz/examples.md#merkle-membership-not-enforced) | `merkle-membership-not-enforced` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [An unchecked witness value becomes public state](https://nightshade.dicksonwu.xyz/examples.md#unconstrained-witness-to-state) | `unconstrained-witness-to-state` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [A freshness check never consumes the nullifier](https://nightshade.dicksonwu.xyz/examples.md#nullifier-check-without-insert) | `nullifier-check-without-insert` | medium | 1 finding, exit 1 | quiet, exit 0 | quiet, exit 0 | | [A private commitment uses fixed randomness](https://nightshade.dicksonwu.xyz/examples.md#predictable-commitment-randomness) | `predictable-commitment-randomness` | medium | 1 finding, exit 1 | quiet, exit 0 | none | ## Synthetic corpus The repository's test corpus pairs each rule with positive cases that should match and corrected, lookalike or other negative cases that should stay quiet. I ran every case declared in the five corpus registries with the installed CLI. The run made 915 distinct CLI scans covering 1161 declarations across 93 rules. 915 scans passed compiler validation, 7 were incomplete and 0 had process failures. A check counts only when the compiler accepted the file and analysis completed. Registries overlap, so the last row counts each (scan, rule, role) once. | Scope | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | --- | ---: | ---: | ---: | ---: | ---: | | `detector-counterexamples/manifest.json` | 20/20 | 20/20 | 20/20 | 0/0 | 0 | | `known-bugs.json` | 105/105 | 105/105 | 105/105 | 0/0 | 0 | | `manifest.json` | 130/130 | 106/106 | 109/121 | 89/96 | 7 | | `policies-manifest.json` | 6/6 | 6/6 | 0/0 | 0/0 | 0 | | `synthetic-regressions.json` | 104/107 | 105/107 | 104/107 | 0/0 | 0 | | **All declarations (overlap kept)** | 365/368 | 342/344 | 338/353 | 89/96 | 7 | | **Unique checks** | 263/266 | 240/242 | 237/252 | 89/96 | 7 | **Misses and control hits.** 3 positive checks were missed, all for [`identity-signature-key`](https://nightshade.dicksonwu.xyz/rules/identity-signature-key.md). 17 corrected or lookalike controls still matched; the corpus labels all of them as expected matches (0 were unexpected), and they get no quiet credit. 7 checks were incomplete and count as failures, not as quiet. 21 synthetic triplets have no mapped target rule; they were scanned but not scored. Corpus scans used budgets of 100,000 steps, 256 paths and 100,000 abstract values, with no suppressions, severity filters or baselines. The run took 1105 seconds on 4 CPU cores. ### Results for each rule | Rule | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | --- | ---: | ---: | ---: | ---: | ---: | | [`always-true-assertion`](https://nightshade.dicksonwu.xyz/rules/always-true-assertion.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`caller-key-zero-entry-review`](https://nightshade.dicksonwu.xyz/rules/caller-key-zero-entry-review.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`caller-supplied-deadline`](https://nightshade.dicksonwu.xyz/rules/caller-supplied-deadline.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`caller-supplied-ledger-equality`](https://nightshade.dicksonwu.xyz/rules/caller-supplied-ledger-equality.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`checked-digest-narrowing`](https://nightshade.dicksonwu.xyz/rules/checked-digest-narrowing.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`checkpoint-splits-atomic-update`](https://nightshade.dicksonwu.xyz/rules/checkpoint-splits-atomic-update.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`circuit-cost`](https://nightshade.dicksonwu.xyz/rules/circuit-cost.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`circuit-work-budget`](https://nightshade.dicksonwu.xyz/rules/circuit-work-budget.md) | 2/2 | 2/2 | 1/1 | 0/0 | 0 | | [`closed-membership-capacity-review`](https://nightshade.dicksonwu.xyz/rules/closed-membership-capacity-review.md) | 6/6 | 3/3 | 2/2 | 10/10 | 0 | | [`conditional-hash-range`](https://nightshade.dicksonwu.xyz/rules/conditional-hash-range.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`configured-membership-capacity-review`](https://nightshade.dicksonwu.xyz/rules/configured-membership-capacity-review.md) | 3/3 | 3/3 | 3/3 | 0/0 | 0 | | [`constant-condition`](https://nightshade.dicksonwu.xyz/rules/constant-condition.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`current-root-policy-mismatch`](https://nightshade.dicksonwu.xyz/rules/current-root-policy-mismatch.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`dead-code`](https://nightshade.dicksonwu.xyz/rules/dead-code.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`declared-secret-publication`](https://nightshade.dicksonwu.xyz/rules/declared-secret-publication.md) | 3/3 | 3/3 | 2/2 | 0/0 | 0 | | [`default-recipient-or-owner`](https://nightshade.dicksonwu.xyz/rules/default-recipient-or-owner.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`destructive-list-reset`](https://nightshade.dicksonwu.xyz/rules/destructive-list-reset.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`discarded-comparison`](https://nightshade.dicksonwu.xyz/rules/discarded-comparison.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`discarded-shielded-send-result`](https://nightshade.dicksonwu.xyz/rules/discarded-shielded-send-result.md) | 5/5 | 5/5 | 5/5 | 0/0 | 0 | | [`duplicate-shielded-mint`](https://nightshade.dicksonwu.xyz/rules/duplicate-shielded-mint.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`duplicated-branch-tail`](https://nightshade.dicksonwu.xyz/rules/duplicated-branch-tail.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`either-payload-mismatch`](https://nightshade.dicksonwu.xyz/rules/either-payload-mismatch.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`enrolled-signature-key-review`](https://nightshade.dicksonwu.xyz/rules/enrolled-signature-key-review.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`exact-balance-threshold`](https://nightshade.dicksonwu.xyz/rules/exact-balance-threshold.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`exported-shielded-descriptor`](https://nightshade.dicksonwu.xyz/rules/exported-shielded-descriptor.md) | 3/3 | 3/3 | 3/3 | 0/0 | 0 | | [`field-arithmetic-wraparound`](https://nightshade.dicksonwu.xyz/rules/field-arithmetic-wraparound.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`field-recomposition-range-review`](https://nightshade.dicksonwu.xyz/rules/field-recomposition-range-review.md) | 5/5 | 4/5 | 4/5 | 0/0 | 0 | | [`forbidden-state-transition`](https://nightshade.dicksonwu.xyz/rules/forbidden-state-transition.md) | 2/2 | 2/2 | 1/1 | 0/0 | 0 | | [`freshness-bound-caller-time`](https://nightshade.dicksonwu.xyz/rules/freshness-bound-caller-time.md) | 12/12 | 12/12 | 12/12 | 0/0 | 0 | | [`generic-witness-maybe-abi`](https://nightshade.dicksonwu.xyz/rules/generic-witness-maybe-abi.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`identity-signature-key`](https://nightshade.dicksonwu.xyz/rules/identity-signature-key.md) | 1/4 | 4/4 | 4/4 | 0/0 | 0 | | [`ignored-validation-result`](https://nightshade.dicksonwu.xyz/rules/ignored-validation-result.md) | 3/3 | 3/3 | 3/3 | 0/0 | 0 | | [`impossible-assertion`](https://nightshade.dicksonwu.xyz/rules/impossible-assertion.md) | 2/2 | 2/2 | 1/1 | 0/0 | 0 | | [`inconsistent-access-control`](https://nightshade.dicksonwu.xyz/rules/inconsistent-access-control.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`inconsistent-keyed-state-guard`](https://nightshade.dicksonwu.xyz/rules/inconsistent-keyed-state-guard.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`ledger-bound-preimage-publication`](https://nightshade.dicksonwu.xyz/rules/ledger-bound-preimage-publication.md) | 7/7 | 12/12 | 1/1 | 0/0 | 0 | | [`low-entropy-hash-disclosure`](https://nightshade.dicksonwu.xyz/rules/low-entropy-hash-disclosure.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`membership-identity-binding-review`](https://nightshade.dicksonwu.xyz/rules/membership-identity-binding-review.md) | 4/4 | 3/3 | 2/3 | 5/5 | 0 | | [`merkle-insert-without-dedupe`](https://nightshade.dicksonwu.xyz/rules/merkle-insert-without-dedupe.md) | 2/2 | 2/2 | 1/2 | 0/0 | 0 | | [`merkle-leaf-binding-review`](https://nightshade.dicksonwu.xyz/rules/merkle-leaf-binding-review.md) | 6/6 | 6/6 | 6/6 | 0/0 | 0 | | [`merkle-membership-not-enforced`](https://nightshade.dicksonwu.xyz/rules/merkle-membership-not-enforced.md) | 5/5 | 5/5 | 5/5 | 0/0 | 0 | | [`missing-role-bootstrap`](https://nightshade.dicksonwu.xyz/rules/missing-role-bootstrap.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`mutually-exclusive-terminal-payout`](https://nightshade.dicksonwu.xyz/rules/mutually-exclusive-terminal-payout.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`native-key-authentication-review`](https://nightshade.dicksonwu.xyz/rules/native-key-authentication-review.md) | 5/5 | 5/5 | 5/5 | 0/0 | 0 | | [`nullifier-check-without-insert`](https://nightshade.dicksonwu.xyz/rules/nullifier-check-without-insert.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`openzeppelin-preconditions`](https://nightshade.dicksonwu.xyz/rules/openzeppelin-preconditions.md) | 6/6 | 6/6 | 6/6 | 0/0 | 0 | | [`operation-intent-policy`](https://nightshade.dicksonwu.xyz/rules/operation-intent-policy.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`permissionless-mint-egress`](https://nightshade.dicksonwu.xyz/rules/permissionless-mint-egress.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`predictable-commitment-randomness`](https://nightshade.dicksonwu.xyz/rules/predictable-commitment-randomness.md) | 2/2 | 2/2 | 1/1 | 0/0 | 0 | | [`public-key-membership-authorization`](https://nightshade.dicksonwu.xyz/rules/public-key-membership-authorization.md) | 9/9 | 6/6 | 6/6 | 3/3 | 0 | | [`public-two-component-domain-review`](https://nightshade.dicksonwu.xyz/rules/public-two-component-domain-review.md) | 6/6 | 5/5 | 3/4 | 4/5 | 1 | | [`publicly-derivable-encryption-secret`](https://nightshade.dicksonwu.xyz/rules/publicly-derivable-encryption-secret.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`publicly-derived-guard-tag`](https://nightshade.dicksonwu.xyz/rules/publicly-derived-guard-tag.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`published-digest-generator-scalar-review`](https://nightshade.dicksonwu.xyz/rules/published-digest-generator-scalar-review.md) | 4/4 | 4/4 | 4/4 | 6/6 | 0 | | [`quorum-signer-uniqueness-review`](https://nightshade.dicksonwu.xyz/rules/quorum-signer-uniqueness-review.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`re-initialization`](https://nightshade.dicksonwu.xyz/rules/re-initialization.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`received-coin-not-validated`](https://nightshade.dicksonwu.xyz/rules/received-coin-not-validated.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`redundant-boolean-branch`](https://nightshade.dicksonwu.xyz/rules/redundant-boolean-branch.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`redundant-self-shielded-receive`](https://nightshade.dicksonwu.xyz/rules/redundant-self-shielded-receive.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`resettable-list-nonce`](https://nightshade.dicksonwu.xyz/rules/resettable-list-nonce.md) | 4/4 | 4/4 | 4/4 | 0/0 | 0 | | [`resettable-memo-nonce-review`](https://nightshade.dicksonwu.xyz/rules/resettable-memo-nonce-review.md) | 2/2 | 2/2 | 7/7 | 0/0 | 0 | | [`secret-binding-divergence-review`](https://nightshade.dicksonwu.xyz/rules/secret-binding-divergence-review.md) | 7/7 | 2/2 | 2/3 | 9/9 | 0 | | [`shadowing`](https://nightshade.dicksonwu.xyz/rules/shadowing.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`shared-module-once-gate`](https://nightshade.dicksonwu.xyz/rules/shared-module-once-gate.md) | 2/2 | 2/2 | 2/2 | 1/1 | 0 | | [`shielded-burn-amount-width`](https://nightshade.dicksonwu.xyz/rules/shielded-burn-amount-width.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`shielded-coin-runtime-width`](https://nightshade.dicksonwu.xyz/rules/shielded-coin-runtime-width.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`shielded-contract-recipient-review`](https://nightshade.dicksonwu.xyz/rules/shielded-contract-recipient-review.md) | 2/2 | 2/2 | 2/2 | 1/1 | 0 | | [`signature-key-identity-exclusion-review`](https://nightshade.dicksonwu.xyz/rules/signature-key-identity-exclusion-review.md) | 3/3 | 3/3 | 2/5 | 1/1 | 0 | | [`signed-effect-input`](https://nightshade.dicksonwu.xyz/rules/signed-effect-input.md) | 3/3 | 3/3 | 3/3 | 0/0 | 0 | | [`source-claim-map-getter-review`](https://nightshade.dicksonwu.xyz/rules/source-claim-map-getter-review.md) | 4/4 | 2/2 | 2/2 | 10/10 | 0 | | [`source-claim-shielded-issuance-review`](https://nightshade.dicksonwu.xyz/rules/source-claim-shielded-issuance-review.md) | 6/6 | 2/2 | 15/16 | 0/1 | 1 | | [`split-witness-identity`](https://nightshade.dicksonwu.xyz/rules/split-witness-identity.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`spoofable-authorization`](https://nightshade.dicksonwu.xyz/rules/spoofable-authorization.md) | 28/28 | 28/28 | 28/28 | 0/0 | 0 | | [`stale-nft-metadata`](https://nightshade.dicksonwu.xyz/rules/stale-nft-metadata.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`stored-schnorr-key-enrollment-review`](https://nightshade.dicksonwu.xyz/rules/stored-schnorr-key-enrollment-review.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`time-dependence`](https://nightshade.dicksonwu.xyz/rules/time-dependence.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`transient-digest-to-ledger`](https://nightshade.dicksonwu.xyz/rules/transient-digest-to-ledger.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`unbounded-mint`](https://nightshade.dicksonwu.xyz/rules/unbounded-mint.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`unconstrained-witness-to-state`](https://nightshade.dicksonwu.xyz/rules/unconstrained-witness-to-state.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`unguarded-sensitive-state-write`](https://nightshade.dicksonwu.xyz/rules/unguarded-sensitive-state-write.md) | 3/3 | 3/3 | 2/2 | 0/0 | 0 | | [`unnecessary-disclose`](https://nightshade.dicksonwu.xyz/rules/unnecessary-disclose.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`unprotected-value-transfer`](https://nightshade.dicksonwu.xyz/rules/unprotected-value-transfer.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`unshielded-refund-endpoint-review`](https://nightshade.dicksonwu.xyz/rules/unshielded-refund-endpoint-review.md) | 5/5 | 1/1 | 1/3 | 7/9 | 2 | | [`unsupported-contract-owner`](https://nightshade.dicksonwu.xyz/rules/unsupported-contract-owner.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`unused-declaration`](https://nightshade.dicksonwu.xyz/rules/unused-declaration.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`write-only-ledger`](https://nightshade.dicksonwu.xyz/rules/write-only-ledger.md) | 2/2 | 1/2 | 1/2 | 0/0 | 0 | | [`zero-amount-complementary-send-review`](https://nightshade.dicksonwu.xyz/rules/zero-amount-complementary-send-review.md) | 4/4 | 2/2 | 3/4 | 7/8 | 1 | | [`zero-amount-initial-membership`](https://nightshade.dicksonwu.xyz/rules/zero-amount-initial-membership.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`zero-amount-set-consumption-review`](https://nightshade.dicksonwu.xyz/rules/zero-amount-set-consumption-review.md) | 2/2 | 2/2 | 4/5 | 8/8 | 0 | | [`zero-amount-unguarded-map-debit-review`](https://nightshade.dicksonwu.xyz/rules/zero-amount-unguarded-map-debit-review.md) | 2/2 | 2/2 | 2/2 | 0/0 | 0 | | [`zero-amount-unshielded-send`](https://nightshade.dicksonwu.xyz/rules/zero-amount-unshielded-send.md) | 1/1 | 1/1 | 1/1 | 0/0 | 0 | | [`zero-default-getter-membership-review`](https://nightshade.dicksonwu.xyz/rules/zero-default-getter-membership-review.md) | 7/7 | 4/4 | 2/2 | 14/14 | 0 | | [`zero-transfer-retained-list-review`](https://nightshade.dicksonwu.xyz/rules/zero-transfer-retained-list-review.md) | 3/3 | 2/2 | 3/4 | 3/5 | 2 | ### All 31 deviations Every failed check, exact-line disagreement and incomplete observation. Rows are manifest declarations, so two rows can describe the same scan. | Registry / case | Rule | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | --- | | known-bugs.json / authorization-raw-native-witness | `spoofable-authorization` | positive | [7] to [6] | exact expectation mismatch | | synthetic-regressions.json / merkle-insert-without-dedupe-39 | `merkle-insert-without-dedupe` | lookalike | [11] to [11] | control hit | | synthetic-regressions.json / write-only-ledger-70 | `write-only-ledger` | corrected | [3] to [3] | control hit | | synthetic-regressions.json / write-only-ledger-70 | `write-only-ledger` | lookalike | [3] to [3] | control hit | | synthetic-regressions.json / identity-signature-key-71 | `identity-signature-key` | positive | [6] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-71 | `identity-signature-key` | lookalike | [7] to [] | exact expectation mismatch | | synthetic-regressions.json / field-recomposition-range-review-86 | `field-recomposition-range-review` | corrected | [7] to [7] | control hit | | synthetic-regressions.json / field-recomposition-range-review-86 | `field-recomposition-range-review` | lookalike | [7] to [7] | control hit | | synthetic-regressions.json / identity-signature-key-96 | `identity-signature-key` | positive | [4,7] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-96 | `identity-signature-key` | lookalike | [5,9] to [] | exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-97 | `identity-signature-key` | positive | [10,13] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-97 | `identity-signature-key` | lookalike | [11,15] to [] | exact expectation mismatch | | manifest.json / zeroAmountSetConsumptionReview40/drafts/consumption40/intentional-zero-consumption.compact | `zero-amount-set-consumption-review` | lookalike | [15] to [15] | control hit | | manifest.json / publicTwoComponentDomainReview43/drafts/owner-domain43/lookalike.compact | `public-two-component-domain-review` | lookalike | [15] to [15] | control hit | | manifest.json / publicTwoComponentDomainReview43/drafts/owner-domain43/opaque-salt-guard.compact | `public-two-component-domain-review` | negative | [] to [] | incomplete or unvalidated; domain-review-evidence-unavailable | | manifest.json / signatureIdentityExclusion46/drafts/signature46/caller-key/lookalike.compact | `signature-key-identity-exclusion-review` | lookalike | [5,9] to [5,9] | control hit | | manifest.json / signatureIdentityExclusion46/drafts/signature46/persistent-key/lookalike.compact | `signature-key-identity-exclusion-review` | lookalike | [12,17] to [12,17] | control hit | | manifest.json / signatureIdentityExclusion46/drafts/signature46/counter/lookalike.compact | `signature-key-identity-exclusion-review` | lookalike | [44,45] to [44,45] | control hit | | manifest.json / complementarySendReview47/drafts/complementary47/boundaries/intentional-same-executable-as-positive.compact | `zero-amount-complementary-send-review` | lookalike | [9] to [9] | control hit | | manifest.json / complementarySendReview47/drafts/complementary47/boundaries/persistent-map-lost-lineage-refusal.compact | `zero-amount-complementary-send-review` | negative | [] to [] | incomplete or unvalidated; complementary-send-proof-unavailable, complementary-send-preparation-unavailable | | manifest.json / secretBindingDivergence49/drafts/secret-binding49/controls/intentional-weaker-same-key.compact | `secret-binding-divergence-review` | lookalike | [18] to [18] | control hit | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/intentional-zero-linked-growth.compact | `zero-transfer-retained-list-review` | lookalike | [12] to [12] | control hit | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/append-then-reset.compact | `zero-transfer-retained-list-review` | negative | [] to [] | incomplete or unvalidated; list-growth-evidence-incomplete, list-growth-preparation-unavailable | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/append-then-pop.compact | `zero-transfer-retained-list-review` | negative | [] to [] | incomplete or unvalidated; list-growth-evidence-incomplete, list-growth-preparation-unavailable | | manifest.json / sourceClaims52/drafts/source-claims52/incomplete-unknown-tag.compact | `source-claim-shielded-issuance-review` | negative | [] to [] | incomplete or unvalidated; source-claim-evidence-unavailable, source-claim-evidence-unavailable | | manifest.json / sourceClaims52/drafts/source-claims52/must-match-intentional-claim.compact | `source-claim-shielded-issuance-review` | lookalike | [6] to [6] | control hit | | manifest.json / independentMembershipIdentity54/drafts/memo-identity44-boundaries/intentional-admin.compact | `membership-identity-binding-review` | lookalike | [20] to [20] | control hit | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/dynamic-map-snapshots.compact | `unshielded-refund-endpoint-review` | negative | [] to [] | incomplete or unvalidated; refund-endpoint-source-unavailable | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/intentional-endpoint.compact | `unshielded-refund-endpoint-review` | lookalike | [58] to [58] | control hit | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/intentional.compact | `unshielded-refund-endpoint-review` | lookalike | [58] to [58] | control hit | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/scalar-ledger-snapshots.compact | `unshielded-refund-endpoint-review` | negative | [] to [] | incomplete or unvalidated; refund-endpoint-source-unavailable | ## Real contracts I reran the installed 0.1.1 CLI on a fixed set of 300 contract roots from 144 repositories. The assembled inputs are not redistributed, so only aggregate counts are published: no project names, paths or findings. All 300 roots stay in every denominator, including the 27 the compiler rejected, which were not scanned. | Outcome | Result | | --- | ---: | | Contract roots | 300 (from 144 repositories) | | Compiler accepted / rejected | 273 / 27 | | Baseline analysis complete | 258 / 300 (86.0%) | | All selected rules complete | 237 / 300 (79.0%) | | Incomplete: budget limit | 12 | | Incomplete: frontend | 1 | | Incomplete: other | 2 | | Process failures / worker-failure roots | 0 / 0 | | Finding instances | 315 | | Wall time, 4 workers | 157.9 s | | Per root: median / p95 / max | 1.36 s / 6.26 s / 32.3 s | The 15 accepted roots without complete baseline analysis are coverage gaps, not clean results. One root did not get the semantic profile it requested and is counted as incomplete. The 315 finding instances are static observations under the default audit selection; I did not review them for accuracy here, so they are not confirmed vulnerabilities. Compiler accept and reject decisions came from the authenticated frozen manifest of the original run; compilers were not rerun. Source hashes for all 300 roots and 66 dependency trees were checked before and after the run and did not change. The earlier pre-release 0.1.0 measurement on the same inputs recorded the same completion counts (258/300 and 237/300) and 315 findings. ## What these numbers do not show - There is no independently established precision or recall estimate for the release. Synthetic tests check defined rule behavior, not unknown vulnerabilities or ecosystem-wide recall. - A quiet corrected or lookalike case shows that the selected rule stopped firing. It does not establish that a contract is secure. - Finding counts on real contracts are static observations, not confirmed vulnerabilities, and completion counts are not accuracy. - Incomplete analysis and compiler rejection are never counted as clean results. - Compiler validation used `--skip-zk`, so it skips proof generation and does not establish runtime behavior. - Results apply to version 0.1.1 and the compiler profiles shown. Other versions can differ. ## Versions and identities | Item | Identity | | --- | --- | | Nightshade CLI | `Nightshade 0.1.1`, installed with npm from the release tarball | | Release tarball SHA-256 | `fee7af6cb124d677e7b62c90da22466dd2c0b5819de9625c11de398635a0a3d6` | | Node / npm | v24.20.0 / 11.19.0 | | Grammar revision | `22de6ee9dbf4b92fe4e2fe3602e53f1e352b79fd` | | Grammar build | `fef63bac6b6120f35b9e64ec29134a40a1fd5a1008ec8e8ae714f523788b5a93` | | Compact compiler 0.31.1 binary | `3054ffa89d7a4dfe24afd31c27ef37e87a95757de0fc24485f335635e26dce57` | | Compact compiler 0.34.0 binary | `baa50cd002492b3163ac3d25bc88904d4c7a40ad490fbeb3b970ea48c7f1d3b5` | | Corpus source checkout | `db27d3bd3c772bd1ab181bcf0c4f86e6f8621893` (release-0.1) | | Public import dependency | [OpenZeppelin compact-contracts](https://github.com/OpenZeppelin/compact-contracts) at `ec1331cd8195694c747d291e8fc8ab6d2914a976` | | Proof run | 2026-10-24, CPU cores 0 to 3 | | Public proof pack | [`nightshade-proof-0.1.1.tar.gz`](https://nightshade.dicksonwu.xyz/downloads/nightshade-proof-0.1.1.tar.gz), SHA-256 `9d95e631dc318006610882911c0d58b7c25fa7754c39b49205c309d2e2e57b3b` | The showcase source fixtures match the files under `tests/corpus` in the repository at v0.1.1 by SHA-256; showcase files that were trimmed say so. The corpus also contains no public audit reproductions in this release, so no result here is a claim about a third-party project. ## Reproduce [Download the proof pack](https://nightshade.dicksonwu.xyz/downloads/nightshade-proof-0.1.1.tar.gz) (`nightshade-proof-0.1.1.tar.gz`, 1.7 MB, 4692 files). SHA-256: `9d95e631dc318006610882911c0d58b7c25fa7754c39b49205c309d2e2e57b3b` It holds the synthetic input snapshot, every raw scan output with its recorded command and exit code, the per-scan configs, these ten examples, the report and the scripts that produced and check them. Local paths in it are replaced with placeholders such as `` and ``, the release tarball is left out (it is the v0.1.1 release asset) and real-contract records keep only the aggregate numbers on the [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md) page. `PUBLIC-PACK.md` inside lists every change. **One example.** Install the release as in [getting started](https://nightshade.dicksonwu.xyz/getting-started.md), download an example's files from the [examples page](https://nightshade.dicksonwu.xyz/examples.md), and run from that folder: ```sh ./.nightshade/node_modules/.bin/nightshade vulnerable.compact --config config.json ./.nightshade/node_modules/.bin/nightshade corrected.compact --config config.json ``` The recorded runs also passed `--compiler` with the path to a Compact 0.34.0 `compactc` to validate each file with the compiler. Expect exit code 1 and one finding for the flagged file, and exit code 0 with no findings for the corrected one. **The corpus.** The fixtures and the five registries are in the repository under [`tests/corpus`](https://github.com/DicksonWu654/nightshade/tree/v0.1.1/tests/corpus) at v0.1.1. The [proof pack](https://nightshade.dicksonwu.xyz/downloads/nightshade-proof-0.1.1.tar.gz) holds the input snapshot, raw outputs, scripts and checksums of this run. To check it without rescanning: ```sh tar -xzf nightshade-proof-0.1.1.tar.gz cd nightshade-proof-0.1.1 sha256sum --check --quiet SHA256SUMS mkdir -p release curl -fL -o release/nightshade-compact-0.1.1.tgz https://github.com/DicksonWu654/nightshade/releases/download/v0.1.1/nightshade-compact-0.1.1.tgz python3 scripts/validate.py ``` `validate.py` recomputes every count on this page from the recorded outputs and checks their hashes. To rescan the synthetic corpus, follow `REPORT.md` in the pack: install the release into the pack, then run `reproduce.py --stage synthetic` with `--toolchains` pointing at Compact 0.31.1 and 0.34.0 compilers and `--oz-root` at the OpenZeppelin checkout above. The real-contract inputs cannot be redistributed, so only the synthetic results are publicly reproducible. Pack SHA-256: `9d95e631dc318006610882911c0d58b7c25fa7754c39b49205c309d2e2e57b3b` (1.7 MB). ===== # Limitations and FAQ > What a Nightshade result means, supported compiler versions, what analysis can miss and what has been measured. Canonical: https://nightshade.dicksonwu.xyz/limitations.html Release: Nightshade 0.1.1 (v0.1.1) ## Does a quiet scan mean my contract is safe? No. Nightshade is a bounded, experimental source analyzer. A complete result means the selected, supported analysis finished. It does not establish compiler validity, transaction feasibility, cryptographic security or whole-contract security. Use it alongside compiler checks, tests and human review. Review diagnostics, `status`, `coverage.baselineStatus` and `coverage.rules`. Unsupported syntax or effects, unresolved imports and exhausted budgets produce gaps. A root without entrypoints does not provide execution coverage. An incomplete scan is never equivalent to a clean scan, including when an explicit CI warning policy lets rule-only gaps pass. ## Which compiler versions are supported? Pinned bounded profiles are 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0. ZKIR2 is the default. ZKIR3 requires explicit selection and is qualified only with 0.34.0. Unlisted versions are unsupported. Pin the profile used by your build; do not change versions merely to clear a diagnostic. See the [exact compiler, language and runtime matrix](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/compiler-onboarding.md#supported-profiles). Rule-specific support can be narrower than engine support. ## What can analysis miss? Path and value tracking are bounded. Abstract paths can overapproximate real execution, so a reported path may be infeasible. Collection relationships, native operations and dynamic calls have restricted coverage. Analysis does not establish arbitrary cross-transaction histories, witness implementation behavior, ledger acceptance or deployed runtime compatibility. Default checks do not infer a complete authorization policy from cross-circuit use of ledger values. A credential-changing circuit can go unreported, including by `inconsistent-access-control`. Declare the required `authorization` policy and review all credential changes explicitly. Intentional disclosure, public-data validation and deliberately rejected transactions can match rules. Severity describes review priority; it does not establish exploitability or impact. Each [rule document](https://nightshade.dicksonwu.xyz/rules.md) explains the evidence and benign matches. ## What has been measured? I reran the released 0.1.1 CLI on a fixed set of 300 contract roots from 144 repositories. 258 of 300 roots finished baseline analysis and 237 of 300 finished every selected rule. The 27 roots the compiler rejected stay in the denominator, and there were 0 process failures. The assembled inputs are not redistributed, so only aggregate counts are published. Completion and finding counts do not measure accuracy. There is no independently established release-wide precision or recall estimate. An earlier precision sample was labeled with model assistance, not by independent auditors, and is not a general accuracy estimate. Synthetic positive, corrected and lookalike tests check defined behavior, not ecosystem-wide recall. The [evaluation page](https://nightshade.dicksonwu.xyz/evaluation.md) has the full tables, every miss and how to reproduce the runs. ## Does Nightshade run my contract or send it anywhere? Normal scans use local sources and imports. They do not execute contracts, require a compiler or fetch dependencies. Installation needs network access. Explicit compiler validation and trusted detector modules execute host code only when selected. The V8 heap setting is not an RSS cap or OS sandbox. ## Can I use macOS or another native platform? The release package targets Linux x86-64/glibc with Node 22 or 24 and libstdc++ providing `GLIBCXX_3.4.31` or newer (Ubuntu 24.04 or Debian 13). On macOS, use the Linux Docker image described in [getting started](https://nightshade.dicksonwu.xyz/getting-started.md). Other native targets need their own parser build and platform validation. ## Where should I report a problem? Use [GitHub issues](https://github.com/DicksonWu654/nightshade/issues) for ordinary bugs and reproducible feature gaps. Follow the [security policy](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/SECURITY.md) and [private vulnerability reporting](https://github.com/DicksonWu654/nightshade/security/advisories/new) for security issues. Include the compiler profile, Nightshade version, scan settings, diagnostics and a minimal example you can share. [Detailed limitations](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/limitations.md) | [Coverage model](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/coverage.md) | [Source and license](https://github.com/DicksonWu654/nightshade) ===== # Changelog > Changes in Nightshade releases 0.1.1 and 0.1.0. Canonical: https://nightshade.dicksonwu.xyz/changelog.html Release: Nightshade 0.1.1 (v0.1.1) ## 0.1.1 - 2026-10-22 - Fixed scans becoming incomplete when the same contract or Nightshade installation is moved to a longer checkout path. - Fixed report identifiers and review output filenames changing after moving a checkout. - When upgrading from 0.1.0, regenerate baselines and suppressions for `secret-binding-divergence-review` and `membership-identity-binding-review`: their fingerprints changed so they stay stable when a checkout moves. Also regenerate `zero-amount-unguarded-map-debit-review` findings that use hashed keys. Report identifiers now stay stable when library callers preview entries or report them in a different order. - Some scans that previously hit a resource limit on long checkout paths now finish and may report additional findings. - Fixed finding fingerprints for filenames containing `$&`, `$'`, `$$`, or a dollar sign followed by a backtick; filenames are now treated literally. ## 0.1.0 - 2026-10-22 - Documented source, local tarball, Docker and GitHub Action installation, a shipped-example quickstart, configuration and suppression workflows, compiler profiles and per-rule review limits. - Added Apache-2.0 distribution notices and package discovery metadata. - Added bounded static analysis for Compact modules, calls, private-data flow and ledger effects, with source-mapped findings and explicit incomplete-analysis diagnostics. - Added text, JSON and SARIF reporting, configurable detector selection, suppressions, offline review maps and GitHub Action support. - Expanded compiler-profile handling, native input validation, collection and control-flow analysis, and UTF-8/UTF-16 source-map handling. - Documented limitations for unsupported syntax, resource budgets, compiler profile differences and review-only findings. [Released changelog](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/CHANGELOG.md) | [Download v0.1.1](https://github.com/DicksonWu654/nightshade/releases/tag/v0.1.1) ===== # caller-supplied-deadline > Caller-supplied time satisfies a ledger-derived delay without a chain-time upper bound. Canonical: https://nightshade.dicksonwu.xyz/rules/caller-supplied-deadline.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `caller-supplied-deadline` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-model | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors caller-supplied-deadline ./.nightshade/node_modules/.bin/nightshade detector show caller-supplied-deadline ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-deadline.md at v0.1.1. Availability: **audit default**; no policy required. Severity/confidence: **medium/medium**. An exported circuit asserts that a caller-supplied `Uint<64>` time has reached a deadline computed by adding to ledger data, but does not assert that the supplied time is at or before protocol block time. A caller may be able to pass the deadline before the intended chain-time wait has elapsed. ```compact const deadline = (announcedAt + noticeSeconds) as Uint<64>; assert(disclose(currentTimestamp >= deadline), "Wait for notice"); ``` The rule follows local aliases and casts in the exported circuit and recognizes an asserted canonical `blockTimeGte` or `blockTimeGt` check of the same time parameter as an upper bound. It looks for a `Uint<64>` parameter whose name contains `time` or is `now`; that name is an admission heuristic, not proof of intended time semantics. Helpers and cross-entrypoint guards are not substituted, and a quiet result does not certify a timelock. Its source traversal has a finite allowance and reports exhaustion as a diagnostic. Check the circuit that records the start time as well as the delayed action. Bind caller time to protocol block time or compare the ledger deadline directly with block time. A known benign match is a circuit that deliberately uses a caller-selected time for an application-defined delay. The `time` or `now` parameter-name test is only an admission heuristic; it does not prove that the value represents protocol time. This local review does not follow helper or cross-entrypoint checks and does not prove a feasible early execution. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line caller-supplied-deadline -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-deadline.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # circuit-cost > Expanded source-operation estimate exceeds the review threshold; this is not a proof-row estimate. Canonical: https://nightshade.dicksonwu.xyz/rules/circuit-cost.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `circuit-cost` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | cfg, resolved-calls, static-loop-bounds | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors circuit-cost ./.nightshade/node_modules/.bin/nightshade detector show circuit-cost ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/circuit-cost.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the source estimate. Use `--min-severity low` to hide informational findings, or `--detectors circuit-cost` to select only this rule. Reports analyzed program entries whose expanded source-operation upper bound exceeds **10,000 units**. Static loops and callees contribute repeated work; both branch alternatives are counted conservatively. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) nests ranges `0..40` and `0..64`, repeating the increment 2,560 times. Its [correction](#example-2) performs one increment. Review accidental repeated work or an unexpectedly large expanded circuit before deciding whether optimization is needed. Recommendation: inspect loop sizes and repeated callees, then measure actual compiler/prover cost. Use [circuit-work-budget](https://nightshade.dicksonwu.xyz/rules/circuit-work-budget.md) for project-specific policy thresholds. ### False positives and limitations Large circuits can be intentional; the fixed threshold is an informational review aid. Units are not proof rows, optimized compiler cost, memory usage, runtime or prover time. A match is not a denial-of-service finding. An unavailable finite estimate or exhausted visit allowance emits an incomplete diagnostic. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/circuit-cost-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { for (const i of 0..40) { for (const j of 0..64) { round.increment(1); } } } ``` #### Example 2 Correction (source: `tests/corpus/informational/circuit-cost-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line circuit-cost -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/circuit-cost.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # discarded-comparison > A comparison not reduced to a source constant is discarded or kept only by unused immutable aliases. Canonical: https://nightshade.dicksonwu.xyz/rules/discarded-comparison.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `discarded-comparison` | | Severity | low | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-source-references, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors discarded-comparison ./.nightshade/node_modules/.bin/nightshade detector show discarded-comparison ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/discarded-comparison.md at v0.1.1. Availability: **default-on**, severity **low**, confidence **high**. Select it alone with `--detectors discarded-comparison`. The rule reports a resolved comparison (`==`, `!=`, `<`, `<=`, `>`, `>=`) whose Boolean outcome is discarded, unless typed scalar source folding resolves the outcome to a constant. It covers expression statements, unused local bindings and unused immutable identity aliases. Disclosure and identity casts preserve this relationship. A sequence discards each prefix result and retains only its tail; prefixes are checked even inside a returned or otherwise consumed sequence. Only entry-reachable root-source circuits are linted. Source-dead branches, empty numeric for ranges and components after a definite rejection are excluded. ### Example and scenario ```compact export circuit increment(limit: Uint<64>): [] { Ownable_assertOnlyOwner(); count < limit; // evaluates the check but discards its Boolean result count.increment(1); } ``` The owner check still enforces authorization. The comparison does not enforce the intended limit through this use. Replace it with `assert(count < limit, "limit reached")`, or consume the outcome in the intended control flow. A Boolean view that returns the comparison is an intentional API and stays quiet. ### Recommendation and limits This is a source-use fact. Operand evaluation, proof constraints and side effects remain; other guards may enforce the same condition. No feasible failure, absence of authorization or deployed vulnerability is claimed. Any non-alias reference conservatively retains a binding, including captures, control flow, computed predicates, aggregates and assignments. One used alias retains an entire fan-out. General computed-result liveness, arbitrary predicate helper forwarding and imported-body linting are outside this rule. Source reachability is structural through the resolved source call graph: a callback used only by a zero-length map/fold can still be linted. This does not establish callback execution or successful execution. Constant folding covers typed scalar source constants, not every tautology or symbolic relationship. ### Evidence and known false positives ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line discarded-comparison -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/discarded-comparison.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # discarded-shielded-send-result > Canonical shielded send or mint metadata is discarded or retained only by unused immutable aliases. Canonical: https://nightshade.dicksonwu.xyz/rules/discarded-shielded-send-result.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `discarded-shielded-send-result` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-source-references, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors discarded-shielded-send-result ./.nightshade/node_modules/.bin/nightshade detector show discarded-shielded-send-result ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 5/5 | 5/5 | 5/5 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/discarded-shielded-send-result.md at v0.1.1. Availability: **default**; informational severity, high confidence in the source observation. No policy required. Informational source-use review; no policy required. Select it alone with `--detectors discarded-shielded-send-result`. The rule observes discarded results from canonical stdlib `sendImmediateShielded` and `sendShielded`, and coin descriptors from `mintShieldedToken`, in structurally reachable root-source circuits. It recognizes expression statements (including transparent disclosure/identity casts) and unused immutable local identity alias chains. Imported aliases keep canonical identity; custom same-name helpers do not match. A helper consisting only of an exact return of a producer or another transparent helper also qualifies. Helpers with setup, branches, partial field returns or computed returns remain outside. Any non-alias reference, including field selection, assignment, capture or return, conservatively retains the result. The returned `ShieldedSendResult` contains `sent: ShieldedCoinInfo` and `change: Maybe`. Review whether the application needs that metadata. Discard does not establish lost funds, spendability or exploitation: wallet or transaction machinery may independently retain metadata. A use of one field silences the rule without proving all metadata is handled correctly. Returning the original input coin does not retain a discarded output descriptor. This bounded source pass has a separate mode/cache and preserves ordinary, validation and comparison allowances. It shares existing constant-source reach, short-circuit and definite-rejection handling. Sequence-prefix discard, arbitrary forwarding helpers, recipient policy and off-chain retention are outside scope. Callback reach is structural and does not prove execution or nonzero iterations. Exhaustion yields an incomplete-rule diagnostic and no findings. Main and Counter scans route this rule through source-only analysis; no engine transfer changes. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line discarded-shielded-send-result -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/discarded-shielded-send-result.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # duplicate-shielded-mint > Identical canonical shielded mint inputs produce a duplicate coin commitment in one transaction. Canonical: https://nightshade.dicksonwu.xyz/rules/duplicate-shielded-mint.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `duplicate-shielded-mint` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, cfg, successful-predicates, canonical-mint-observations | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors duplicate-shielded-mint ./.nightshade/node_modules/.bin/nightshade detector show duplicate-shielded-mint ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. Two mint calls use identical token, amount, nonce and recipient inputs on the same path. Full example: https://nightshade.dicksonwu.xyz/examples.md#duplicate-shielded-mint ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Duplicate shielded mint commitment [duplicate-shielded-mint] vulnerable.compact:7:3 7 | mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); | ^ rewardTwice invokes mintShieldedToken twice with provably identical token domain, amount, nonce and active recipient on one modeled successful history. The pinned library derives the same coin commitment in this contract context; duplicate commitments are rejected by the ledger. This is a transaction availability defect, not proof of token theft or a generic commitment-opening vulnerability. Source: vulnerable.compact:6:3 Call path: rewardTwice → mintShieldedToken Remediation: Use a distinct nonce for each minted output, for example evolveNonce with a distinct index. Review freshness across separate transactions independently. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Give the second mint a distinct nonce. ```compact // Owned synthetic duplicate-mint regression. import CompactStandardLibrary; export circuit rewardTwice(nonce: Bytes<32>, recipient: ZswapCoinPublicKey): [] { const to = left(disclose(recipient)); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(0,nonce)),to); mintShieldedToken(pad(32,"sdk:reward"),1,disclose(evolveNonce(1,nonce)),to); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/duplicate-shielded-mint.md at v0.1.1. Availability: **default-on**, medium severity, high confidence for operand equality. ### Description, example and scenario ```compact mintShieldedToken(domain, 1, nonce, recipient); mintShieldedToken(domain, 1, nonce, recipient); ``` Two canonical library calls on the same modeled successful transaction history have provably identical token domain, amount, nonce and active recipient. The contract address is unchanged within that history. The library derives the same coin commitment, which the ledger rejects as a duplicate. This is a transaction availability defect; the rule does not establish theft or runtime feasibility. ### Recommendation Use a different nonce for each minted output. `evolveNonce` derives nonces from an index and a prior nonce; use distinct indices for different outputs. Review freshness across separate transactions independently. ### Evidence and known false positives Resolved canonical mint calls, immutable operand identities/constants and enforced successful-path equalities establish equality. Re-evaluating `evolveNonce` with identical inputs also establishes equality. A saved opaque computed nonce retains an observer-only immutable snapshot; separately computed unknown values do not become equal through shared dependencies. Inactive Either payloads are ignored; active tags and addresses are retained. Separate histories, rejected paths, independent unknown witnesses, changing ledger revisions, different amounts and domains, and application namesakes do not create duplicates. Intentionally rejected test transactions may be review matches. Generic repeated `persistentCommit` openings are not diagnosed as a vulnerability. Cross-transaction nonce freshness, custom mint/commitment implementations and symbolic reasoning are outside scope. Unknown operands do not prove a duplicate; exhausted observation or equality budgets are rule/entry-scoped incomplete, preserve baseline findings and keep the overall scan incomplete. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line duplicate-shielded-mint -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/duplicate-shielded-mint.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#duplicate-shielded-mint) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # duplicated-branch-tail > Terminating branch repeats its immediate following expression and return tail. Canonical: https://nightshade.dicksonwu.xyz/rules/duplicated-branch-tail.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `duplicated-branch-tail` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors duplicated-branch-tail ./.nightshade/node_modules/.bin/nightshade detector show duplicated-branch-tail ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/duplicated-branch-tail.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the resolved source observation. Use `--min-severity low` to hide informational findings. Reports one to seven expression statements and an explicit return copied between the end of a terminating branch and its immediate following continuation. Both copies must resolve to the same symbols, operations, types and expression tree. This is source duplication across alternative routes, not duplicate execution. ### Example and review scenario For example: ```compact if (disclose(flag)) { round.increment(1); return []; } round.increment(1); return []; ``` Each route increments once. Consider sharing the tail after any branch-specific work. The finding is a source-quality observation, not an authorization or monetary defect. ### False positives and limitations Authors may deliberately keep alternative routes visually independent. Identical resolved source is the fact reported; removal or hoisting is a review decision. Preserve return behavior, proof constraints, disclosure and transaction ordering. No optimized compiler/prover cost reduction is claimed. Resolved circuit bodies in the compilation unit are examined, including imported instances and calls in source-excluded code. Unresolved unused library APIs are outside this observation; this is not a whole-library analysis. Unknown conditions retain both alternatives; source-constant excluded branches and unreachable suffixes are quiet. Bindings, callbacks, nested control inside the copied tail, implicit returns, longer tails and merely value-equivalent expressions are outside the contract. Same-name references that resolve differently stay quiet. Exhausted source traversal produces explicit rule-scoped incomplete diagnostics for every entry. Baseline transfer completion and unrelated rules remain independently reported. With no entry row, exhaustion retains an explicit root diagnostic. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line duplicated-branch-tail -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/duplicated-branch-tail.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # either-payload-mismatch > A native Either's known inactive arm reaches an output, state effect or successful effect gate. Canonical: https://nightshade.dicksonwu.xyz/rules/either-payload-mismatch.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `either-payload-mismatch` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-types, successful-either-selections, public-sinks, state-writes, predicates | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors either-payload-mismatch ./.nightshade/node_modules/.bin/nightshade detector show either-payload-mismatch ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/either-payload-mismatch.md at v0.1.1. Availability: **default-on**; select only this rule with `--detectors either-payload-mismatch`; severity **medium**, confidence **high**. Explicit selection replaces the default set. The rule reports a canonical native Either arm selection when that receiver's immutable `is_left` tag selects the other arm on a modeled successful history, and the selected payload reaches a public output, a state/transaction effect, an effect's actual control dependence, or a non-tautological assertion gating an effect. It uses typed receiver snapshots, not common witness provenance. Imported and nominal native aliases retain their identity; same-shaped user structs are quiet. ### Example and scenario ```compact export circuit gatedIncrement(allowed: Either, claim: Field): [] { assert(!allowed.is_left, "right admission"); assert(allowed.left == claim, "admission"); // validates the inactive arm round.increment(1); } ``` Validate `allowed.right` after requiring the right tag. Both payload fields are represented in Compact; projecting one does not itself constrain `is_left`. The finding is an established tag/selection mismatch with a modeled consequence, not a proof of an authorization bypass or deployed exploit. ### Recommendation and limits Check the same receiver's tag and use its selected payload. An assertion after an effect can still constrain successful completion because effects are atomic. A tag check on replacement ledger storage cannot repair a retained old snapshot. Independent dynamic Map lookups do not share a definite tag merely because their regions may alias. Helpers, destructuring, aggregate payloads and aliases use the same observation transfer. Bare unused reads, unknown tags, same-shaped application structs, tautological assertions, identical total/effect-free conditional arms, and branches that neither reject nor control an effect stay quiet. A direct untransformed arm copied into an explicit native Either construction establishes a new receiver choice; that copy alone is exempt. Subsequent selection uses the new receiver's tag. Computations over the original arm preserve their dependencies. General variant lifecycle/protocol validation, branch-rejection proofs for effects after joins, unconstrained witness-output dependence, and correlated may-history certificates are outside this rule. ### Evidence and known false positives Branch-expanding entries first try a `conservative-absence` certificate (see docs/coverage.md): a complete conservative may-view in which every native Either payload selection reads the arm selected by its receiver tag, refined to that constant by the joined current constraints. Any unknown or inactive tag is a candidate and falls back to exact observation with the remaining allowance. Observation shares the configured work/value allowances, retains at most 256 reads per history, 4,096 Boolean/control observations, conditional chains of at most 64 observations, and limits consequence traversal to 200,000 work units. `either-evidence-budget`, `either-finding-budget`, or missing exact evidence produce an explicit incomplete diagnostic. Incomplete roots supply no negative coverage claim. Instruction/reference and requested-cache/uncached tests cover these semantics; cached requests currently use the uncached transfer. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line either-payload-mismatch -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/either-payload-mismatch.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # field-recomposition-range-review > Enforced Field recomposition retains quotient/remainder envelopes beyond the modulus. Canonical: https://nightshade.dicksonwu.xyz/rules/field-recomposition-range-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `field-recomposition-range-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | owned-numeric-expressions, successful-predicates, resolved-types | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors field-recomposition-range-review ./.nightshade/node_modules/.bin/nightshade detector show field-recomposition-range-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 5/5 | 4/5 | 4/5 | 0/0 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | synthetic-regressions.json / field-recomposition-range-review-86 | corrected | [7] to [7] | control hit | | synthetic-regressions.json / field-recomposition-range-review-86 | lookalike | [7] to [7] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/field-recomposition-range-review.md at v0.1.1. Availability: default. Severity: info. Confidence: high. `field-recomposition-range-review` reports an informational source observation. It reviews an enforced Field equality (including negated comparisons) whose owned numeric expression is a shallow `quotient * constant + remainder`, allowing commuted operands. The constant must be a power of two greater than one. Both scalar operands must preserve an exact raw entry-parameter or witness source identity, have no ledger dependencies, and be distinct after successful scalar equality normalization. Names do not establish quotient/remainder intent. Native results, ledger reads and derived operands are outside this first shape. The rule uses existing numeric observation machinery and reconstructs integer constraints separately for each completed successful history. Equality aliases, checked numeric casts, retained integer domains, orderings and exclusions can constrain the exact operand envelopes. It reports when their mathematical multiply-plus-add upper endpoint reaches the Field modulus. Histories at the same entry, equality site and matched side share a stable finding with separate retained envelopes; bounds from sibling histories are never combined. The report establishes only a retained envelope fact. It does not establish joint operand feasibility, integer decomposition intent, ambiguity, an invalid execution, proof failure or deployed impact. Relation matching is shallow: expanded Boolean formulas, recursive algebra and alternate decompositions are outside scope. Successful equality against the modular result is not an integer range certificate. Missing exact evidence, unfinished requested entries, contradictory constraint reconstruction and allowance exhaustion produce rule-scoped incomplete diagnostics and no partial finding set. The rule distinguishes a bounded quotient from a wider value that can wrap during recomposition. Compiler acceptance is checked separately; no proof or runtime execution is used. Intentional modular arithmetic can satisfy the same source shape. Review whether integer reconstruction is intended before changing a bound; the envelope is not proof the operands jointly reach it or a concrete execution wraps. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line field-recomposition-range-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/field-recomposition-range-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # freshness-bound-caller-time > Caller-supplied time reaches a security-sensitive effect without a canonical block-time freshness bound. Canonical: https://nightshade.dicksonwu.xyz/rules/freshness-bound-caller-time.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `freshness-bound-caller-time` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-model, state-writes, public-sinks | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors freshness-bound-caller-time ./.nightshade/node_modules/.bin/nightshade detector show freshness-bound-caller-time ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. The circuit accepts a caller-supplied time window without bounding it against chain time. Full example: https://nightshade.dicksonwu.xyz/examples.md#freshness-bound-caller-time ```compact pragma language_version >= 0.23; import CompactStandardLibrary; export ledger startedAt: Uint<64>; export ledger authenticated: Boolean; constructor() { startedAt = 0; authenticated = false; } export circuit authenticate(expectedTimeWindow: Uint<64>): [] { assert(disclose(expectedTimeWindow >= startedAt), "window"); startedAt = disclose(expectedTimeWindow); authenticated = true; } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Caller time is not bound to protocol time [freshness-bound-caller-time] vulnerable.compact:14:3 14 | startedAt = disclose(expectedTimeWindow); | ^ authenticate accepts caller-supplied expectedTimeWindow and uses it in a state-changing or public effect without an asserted canonical block-time bound. A delayed, future-dated or stale proof may remain valid outside the intended freshness window. This source/effect review does not establish transaction ordering or exploitability. Source: vulnerable.compact:12:29 Call path: authenticate Remediation: Compare the caller value with block time using canonical blockTimeGte/blockTimeGt and blockTimeLte/blockTimeLt checks, or derive the deadline solely from a kernel-bound timestamp. Keep the bound on the same successful path as the state-changing effect. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Bound the caller's time with blockTimeGte before using it. ```compact pragma language_version >= 0.23; import CompactStandardLibrary; export ledger startedAt: Uint<64>; export ledger authenticated: Boolean; constructor() { startedAt = 0; authenticated = false; } export circuit authenticate(expectedTimeWindow: Uint<64>): [] { assert(blockTimeGte(disclose(expectedTimeWindow)), "future window"); assert(disclose(expectedTimeWindow >= startedAt), "window"); startedAt = disclose(expectedTimeWindow); authenticated = true; } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 12/12 | 12/12 | 12/12 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/freshness-bound-caller-time.md at v0.1.1. Availability: **default source/effect review**, no policy required. Severity/confidence: **medium/medium**. This rule flags an exported circuit that uses caller-supplied time to enforce a freshness or deadline condition without binding that value to a kernel timestamp on the same successful path. A parameter name or `Uint<64>` type alone does not establish that a value is time. Remediation: bind the supplied time to chain time in the same successful path, or derive the gate from a kernel-bound timestamp. Review both the timestamp-recording and delayed-action circuits. A deliberate caller-selected time source can match and is not automatically a defect. The source/effect review does not infer time semantics from names or comments, follow every helper-mediated constraint, or prove a feasible stale-time execution. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line freshness-bound-caller-time -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/freshness-bound-caller-time.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#freshness-bound-caller-time) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # identity-signature-key > A successful history passes a known identity point to the pinned Schnorr verifier. Canonical: https://nightshade.dicksonwu.xyz/rules/identity-signature-key.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `identity-signature-key` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, constants, successful-signature-calls | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors identity-signature-key ./.nightshade/node_modules/.bin/nightshade detector show identity-signature-key ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/4 | 4/4 | 4/4 | 0/0 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | synthetic-regressions.json / identity-signature-key-71 | positive | [6] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-71 | lookalike | [7] to [] | exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-96 | positive | [4,7] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-96 | lookalike | [5,9] to [] | exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-97 | positive | [10,13] to [] | miss, exact expectation mismatch | | synthetic-regressions.json / identity-signature-key-97 | lookalike | [11,15] to [] | exact expectation mismatch | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/identity-signature-key.md at v0.1.1. Availability: **default-on**; severity **medium**, confidence **high**. No application policy is needed. This rule reports only a statically known identity key on a modeled successful history, not every unconstrained verification key. ### Example and scenario ```compact assert(jubjubSchnorrVerify<1>(message, signature, default), "signature"); round.increment(1); ``` An identity verification key does not supply the intended signer authentication. The known-key diagnosis is factual; the analyzer does not construct a signature, prove exploitability, or infer a deployed application's intended signer. ### Recommendation Reject the identity key and bind the verification key to the intended trusted signer. A nonidentity check alone does not establish trusted ownership or complete key validity. The pinned stable 0.35.0 and 0.35.0-rc.1 standard-library verifiers reject identity keys internally; profile support is a ZKIR2 subset, and upgrades need compatibility review. ### Evidence and known false positives Canonical resolved stdlib calls retain separate key operands on successful histories. Aliases, helpers, known zero multiplication and caller equality refinements are supported. Rejected histories and same-named application circuits are quiet. No new observation is enabled in projects without the canonical verifier. Observation exhaustion remains explicitly incomplete. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line identity-signature-key -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/identity-signature-key.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # ignored-validation-result > A canonical signature verifier's Boolean outcome is discarded or retained only by unused local aliases. Canonical: https://nightshade.dicksonwu.xyz/rules/ignored-validation-result.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `ignored-validation-result` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, resolved-source-references | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors ignored-validation-result ./.nightshade/node_modules/.bin/nightshade detector show ignored-validation-result ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. The signature verifier returns a boolean, but the state change proceeds without asserting that it is true. Full example: https://nightshade.dicksonwu.xyz/examples.md#ignored-validation-result ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Synthetic regression mutation; no upstream-project finding is claimed. pragma language_version >= 0.20; import CompactStandardLibrary; export ledger round: Counter; export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); jubjubSchnorrVerify<1>(msg, sig, pk); round.increment(1); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Signature verification outcome is discarded [ignored-validation-result] vulnerable.compact:23:3 23 | jubjubSchnorrVerify<1>(msg, sig, pk); | ^ The Boolean outcome of the canonical jubjubSchnorrVerify is discarded. The call may impose internal constraints, but its signature-validity result does not constrain this caller through this use. Remediation: Assert the verification result, or reject the false branch before the transaction can succeed. Preserve intentional Boolean checker APIs; suppress intentional verifier-only tests with a reason. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Assert the verifier's result. ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Synthetic regression mutation; no upstream-project finding is claimed. pragma language_version >= 0.20; import CompactStandardLibrary; export ledger round: Counter; export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { assert(pk != default, "nonidentity signer"); assert(jubjubSchnorrVerify<1>(msg, sig, pk), "signature"); round.increment(1); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 3/3 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/ignored-validation-result.md at v0.1.1. Availability: **default-on**; select only this rule with `--detectors ignored-validation-result`; severity **medium**, confidence **high**. Explicit selection replaces the default detector set. The rule reports a canonical `CompactStandardLibrary.jubjubSchnorrVerify` call whose Boolean outcome is directly discarded, or assigned to a local whose identity aliases have no non-alias source use. Unused fan-out and alias chains report at the original verifier expression (`unused-alias-chain` metadata). Imported callable aliases retain canonical identity; same-named application circuits are quiet. A resolved transparent helper chain whose only statement returns this verifier outcome is also recognized, including imported/generic helpers and explicit disclosure/identity casts of that result. The finding stays at the discarding caller; metadata lists the forwarding circuits. Helpers that enforce the result internally, add setup/statements or compute another Boolean are excluded. Only entry-reachable root-source circuits are linted, excluding source-dead branches, empty static loops and statements after a literal-false rejection or unconditional return. ### Example and scenario ```compact export circuit signedIncrement(msg: Vector<1, Field>, sig: JubjubSchnorrSignature, pk: JubjubPoint): [] { jubjubSchnorrVerify<1>(msg, sig, pk); // outcome is discarded round.increment(1); } ``` A signed operation may appear to verify its authorization but succeed without requiring the verifier's outcome. Assert the returned Boolean or reject its false branch before the transaction succeeds. Rejection after a write also enforces the check: Compact transaction effects are atomic. ### Recommendation and limits The finding is a source fact about discarding the outcome, not a proof of absent authentication or feasible unauthorized execution. Internal verifier constraints remain, including the RC nonidentity-key assertion. A reference through a simple local alias, disclosure or identity cast follows the alias's uses. Any other reference conservatively preserves the result, including assignments, captures, checker returns, Boolean control, aggregates and computed expressions. A single used alias preserves the result across fan-out. Complex unused computations, nontransparent application forwarders, imported helper body linting, custom verifiers and general non-assert uses are outside this rule. No general validation-enforcement claim is made. ### Evidence and known false positives ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line ignored-validation-result -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/ignored-validation-result.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#ignored-validation-result) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # impossible-assertion > A nonliteral assertion fails on every reaching path, or an entry has no successful path. Canonical: https://nightshade.dicksonwu.xyz/rules/impossible-assertion.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `impossible-assertion` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | cfg, constants, path-constraints, failed-assertions, assertion-reaches, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors impossible-assertion ./.nightshade/node_modules/.bin/nightshade detector show impossible-assertion ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/impossible-assertion.md at v0.1.1. Availability: **default**; no policy required. Severity **medium**, confidence **high** for modeled universal rejection. Reports a nonliteral-false assertion that fails on every modeled path reaching its source site, with complete caller coverage. It can also report a completely analyzed entrypoint with no successful path, without duplicating an entry already explained by an assertion finding. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) requires `flag` and then its negation. The [correction](#example-2) keeps compatible checks. Review contradictory validation when an intended entrypoint appears unusable; inspect the preceding constraints as well as the reported assertion. Recommendation: preserve guards that reject invalid inputs while allowing the intended inputs to succeed. Correct contradictory operands or document an intentionally disabled entrypoint. Checked arithmetic and casts may also explain an entrypoint-level rejection. ### False positives and limitations Deliberately disabled entrypoints can match. Ordinary rejecting guards are quiet if some reaching invocation passes, even if that caller aborts later. Literal `assert(false)` revert sites are suppressed as assertion findings; nonliteral constant-false expressions remain reportable. Incomplete or unselected potential callers block universal assertion claims. A finding concerns modeled invocation constraints, not cross-transaction reachability or a successful state change. Unknown effects and exhausted budgets remain incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/contradictory-assertion.compact`). ```compact pragma language_version >= 0.26.0; export circuit verify(flag: Boolean): [] { assert(flag, "flag required"); assert(!flag, "flag forbidden"); } ``` #### Example 2 Correction (source: `tests/corpus/safe/contradictory-assertion.compact`). ```compact pragma language_version >= 0.26.0; export circuit verify(flag: Boolean): [] { assert(flag, "flag required"); assert(flag, "flag still required"); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line impossible-assertion -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/impossible-assertion.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # ledger-bound-preimage-publication > A private preimage checked against a ledger hash is also published on a potential successful path. Canonical: https://nightshade.dicksonwu.xyz/rules/ledger-bound-preimage-publication.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `ledger-bound-preimage-publication` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, cfg, private-provenance, hash-bindings, public-sinks | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors ledger-bound-preimage-publication ./.nightshade/node_modules/.bin/nightshade detector show ledger-bound-preimage-publication ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. A secret checked against a stored hash is then written directly to public state. Full example: https://nightshade.dicksonwu.xyz/examples.md#ledger-bound-preimage-publication ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Field; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(secret); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Ledger-bound private preimage is published [ledger-bound-preimage-publication] vulnerable.compact:12:3 12 | published = disclose(secret); | ^ Private value from ownerSecret reaches ledger-write published without a hiding transformation. A hash of this value is asserted equal to ledger ownerHash on the same potential successful path. Ledger operation data is public. If an untrusted observer obtains a reusable authentication secret through this boundary, secrecy is lost. An intentional reveal protocol may permit this flow. Source: vulnerable.compact:10:18 Constraint: vulnerable.compact:11:3 Call path: update Remediation: Keep reusable authentication preimages private; publish a suitable commitment or non-secret result. If this is intentional reveal, confirm that the revealed value grants no remaining authority and document that policy. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Publish the hash instead of the secret. ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Bytes<32>; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(persistentHash(secret)); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 2/2 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 7/7 | 12/12 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/ledger-bound-preimage-publication.md at v0.1.1. Availability: **default**; no policy required. Severity **medium**, confidence **medium**. Reports the same raw private source reaching a public sink and having a hash containing that exact source asserted equal to preexisting ledger data on one modeled successful path. The hash may include constants or public context such as a ledger sequence; a second private ingredient is outside this contract. Ledger writes and ledger-operation arguments are public sinks; exported returns are application outputs and are not necessarily published on the ledger. ### Example and review scenario The compiler-qualified owned [direct fixture](#example-1) checks a witness preimage against `ownerHash` and also publishes that preimage. Review whether this is a reusable authentication secret or an intentional reveal. The [correction](#example-2) publishes only the digest: ```compact assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(persistentHash(secret)); ``` Recommendation: keep reusable preimages private and publish an appropriate non-secret result. For a reveal protocol, confirm that disclosure grants no remaining authority and document the intended boundary. A digest alone does not guarantee secrecy for low-entropy input. ### False positives and limitations Intentional commit/reveal can match. The rule does not prove concrete feasibility, reusability, intended authentication, or deployed exploitability. Transformed preimages, hashes with multiple private sources and cryptographic equivalence are outside the evidence contract. Identity-preserving numeric casts and full-width Bytes slices retain raw provenance. `disclose` alone is permission, not a sink; discarded disclosure is quiet. Unknown effects and exhausted budgets remain incomplete. Fixture labels concern this detector only; see the [corpus qualification scope](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/evaluation.md). Real-source regression: the recorded bulletin-board mutation publishes a key bound by `hash([domain, sequence, secret])`. It is now detected; the hash-only correction and separate-witness lookalike remain quiet. Private-controlled context, transformed secrets and may-alias source unions do not establish this single-preimage evidence. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Direct fixture (source: `tests/corpus/vulnerable/direct.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Field; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(secret); } ``` #### Example 2 Correction (source: `tests/corpus/safe/hash-only.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger ownerHash: Bytes<32>; export ledger published: Bytes<32>; witness ownerSecret(): Field; constructor(initialHash: Bytes<32>) { ownerHash = disclose(initialHash); } export circuit update(): [] { const secret = ownerSecret(); assert(persistentHash(secret) == ownerHash, "not authorized"); published = disclose(persistentHash(secret)); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line ledger-bound-preimage-publication -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/ledger-bound-preimage-publication.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#ledger-bound-preimage-publication) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # low-entropy-hash-disclosure > A published direct hash has one private input drawn from a small declared domain. Canonical: https://nightshade.dicksonwu.xyz/rules/low-entropy-hash-disclosure.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `low-entropy-hash-disclosure` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-types, private-provenance, public-sinks, direct-hash-inputs | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors low-entropy-hash-disclosure ./.nightshade/node_modules/.bin/nightshade detector show low-entropy-hash-disclosure ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/low-entropy-hash-disclosure.md at v0.1.1. Availability: **default-on**; select only this rule with `--detectors low-entropy-hash-disclosure`; severity **medium**, confidence **high**. Explicit selection replaces defaults. The rule reports an exact published native digest with one direct private source whose selected private leaf type has at most **65,536** values. Boolean, small Uint, Bytes and enum domains (including nominal aliases) are supported. Public ledger context does not add secret uncertainty. The bound is a type-domain upper bound, not an entropy estimate, a secrecy policy or proof that an application has a vulnerability. ### Example and scenario ```compact export circuit recordVote(vote: Boolean): [] { voteDigest = disclose(persistentHash(vote)); } ``` A digest of a Boolean is drawn from a two-candidate input domain. Hashing alone supplies no useful hiding for this vote when its digest is published. A protocol that intends to keep votes hidden should use a suitable commitment with sufficiently unpredictable private opening randomness, then reveal it only at the intended phase. The pinned standard-library documentation explicitly requires acknowledged disclosure for hashes and distinguishes commitments with random openings; `disclose` itself is permission, not secrecy protection. Publishing a low-domain digest can be intentional when the input is already public or the protocol explicitly accepts that disclosure. Review the actual privacy requirement; a match is a domain-size warning, not proof that a secret or exploitable value has been exposed. ### Evidence and limitations Immutable typed native digest inputs follow aliases, helpers and aggregate copies to public sinks. Projected fields retain their leaf type. A raw input published on the same successful history is public context, including later atomic writes; publishing a transformed salt does not establish publication of its preimage. A hash comparison or hash-dependent branch is not publication of the digest. Private-salted/multiple-private-source hashes, arbitrary transformed inputs, commitments and domains above the threshold stay outside this rule's scope. There is no claim of general entropy analysis or multi-secret guessing. An exported return is an application-output boundary, not necessarily a globally public ledger. Raw witness and entry-parameter origins are both considered. Traversal is bounded at 200,000 work units and domain expansion at 4,096 units, with saturation above the threshold. Exhaustion produces `hash-domain-budget` and incomplete status, never a clean result. Ordinary unsupported effects and analysis budgets also remain incomplete. A bounded applicability check enables exact typed digest observation for reachable native hashes with a represented small-domain input leaf, nonempty Bytes inputs that may retain constructed byte leaves, and native hash callbacks. It conservatively enables observation if its scope allowance is exhausted. Observation bypasses general fold compression. Three exact compressed transfers remain available: a total hash-order choice whose arms hash the same typed leaves in another order, the native scalar little-endian comparison fold, and the bounded pure-fold join when all callback alternatives are equal up to the order of direct-digest input items (for example the standard-library Merkle path fold). Their elided selector, branch-constraint or byte-partition identities (and identities computed from them) may not reach a published digest input, a constraint relating them to other values, or a storage key/location; any such dependency reports `observation-compression-dependency` and leaves the rule incomplete for that entry. Summaries are not cached across these transfers. Branch-expanding entries first try a `conservative-absence` certificate (see docs/coverage.md): a complete conservative may-view in which no evaluated native hash has a direct input leaf that is a joined value with a raw dependency, or a represented raw private leaf whose declared domain is small, unless the input also has two distinct represented raw private leaves whose declarations are never published raw on any possible sink and never a raw operand of a constraint or checked narrowing (so both stay private and non-constant on every history). Otherwise publication, salts and the single-private-leaf condition are ignored, so a certificate implies no finding on any exact history. Candidates fall back to the exact pass with the remaining entry allowance; the certificate never reports findings. It may complete fewer contracts than a scan with this rule disabled under the same budgets; missing exact input evidence gives `hash-domain-evidence-unavailable`. This rule consumes immutable typed inputs from the shared native digest transfer; it does not perform candidate enumeration or contact a contract or author. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line low-entropy-hash-disclosure -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/low-entropy-hash-disclosure.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # merkle-leaf-binding-review > Checked Merkle path leaves lack binding to supplied lookup inputs or exact Field hash write candidates. Canonical: https://nightshade.dicksonwu.xyz/rules/merkle-leaf-binding-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `merkle-leaf-binding-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | merkle-observations, successful-predicates, digest-inputs, mint-quantity-observations, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors merkle-leaf-binding-review ./.nightshade/node_modules/.bin/nightshade detector show merkle-leaf-binding-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 6/6 | 6/6 | 6/6 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-leaf-binding-review.md at v0.1.1. Availability: **default-on**; no policy required. Direct Field/Bytes<32> path-lookup review is **info/medium**; Field hash-write intent review is **info/low**. `merkle-leaf-binding-review` is an informational intent review. It finds modeled successful histories where a canonical checked Merkle root accompanies an exact recomputed hash candidate influencing a Field ledger write, without a required equality between that root operation's original Field leaf and candidate. The operations can be intentionally independent. Root enforcement alone is not a security flaw or evidence of exploitability. The narrow candidate scope is a Field `directDigest` snapshot at a write operand, or within exact `numericExpression` addition/subtraction/multiplication operands. The final hash of a summarized nonzero-depth canonical Merkle root remains a candidate through a separate marker; it does not invent a native hash preimage. Constant hash inputs remain candidates. Successful equality predicates provide transitive binding, and constructing a path with the exact candidate binds it by identity. Equality never comes from shared provenance or storage regions. Whitelist-only histories without a recomputed candidate remain quiet. Analysis must enable existing Merkle, digest-input and mint-quantity observers, retain all successful predicates, and disable fold/hash compression. The detector checks the observer evidence markers, but the caller is responsible for selecting uncompressed caller histories. The isolated observer can summarize the pure root helper from the exact pinned 0.30.0, 0.31.1 and 0.34.0 ZKIR2 standard libraries, for Field/Bytes<32> leaves and depths 0 through 32. The transfer retains the whole immutable path identity and its represented dependence without enumerating path directions. It adds no leaf equality, root trust or membership. Argument evaluation, effects and aborts happen normally; source-work estimates stay unchanged. The ordinary call-depth allowance includes the entry helper reached by a nonempty path fold. A zero-depth root does not spend that callback frame. Other profiles and shapes use ordinary interpretation or explicit incomplete diagnostics. The ordinary interpreter remains a small-depth oracle, and baseline analysis is unchanged. Incomplete entries and constructors are excluded. Equality/root decoding and candidate traversal are bounded; missing required evidence or exhausted budgets produce diagnostics and discard findings from that run. Root enforcement reuses the revision-qualified Merkle predicate snapshots. Leaf matching uses the original root operand, so a later replacement cannot satisfy an earlier leaf obligation. Separate proof and witness invocation identities remain distinct; optional bindings only cover histories on which they are enforced. Aborted histories have no successful effects to report. The separate hash-write arm excludes Bytes leaves, aggregates, control-only hash dependencies, commitments, arbitrary derived expressions without numeric snapshots, hashes lost before any observed path lookup/write operand, and effects outside modeled Field ledger writes except the direct path-lookup input shape. Such shapes are outside this rule's restricted applicability; it is not an exhaustive candidate-computation analysis. No application authentication intent is inferred. Focused tests cover instruction/reference engines with cached/uncached summaries, optional/transitive checks, independent proofs, stored operand replacement, constructed paths, constant-input candidates, aborts and evidence budgets. Compiler validation uses compactc 0.34.0 with `--skip-zk`; no deployed contracts, runtime execution or proof execution are involved. Direct canonical `MerkleTreePath` witnesses also retain their lookup operands. For a checked exact returned path, a Field or Bytes<32> lookup input not required equal to its leaf on that successful history reports info/medium. The argument must have the leaf's exact type; original argument positions remain in the report. Passing a candidate to a witness never binds the returned leaf. Immutable full-path matching distinguishes separate invocations, retained snapshots and a rebuilt path. Inputs that are indices or independently validated values can intentionally differ and require human review. Type-scoped equality keys distinguish scalar representations. Byte/Field conversions and round trips supply dependence, not equality with the original input. Root and leaf checks may occur in either order on the same successful history; this is not a dominating-before-effect claim. Direct Bytes<32> leaf lookups also support the canonical NoLeafHash helper. Paths nested in witness-returned aggregates, arbitrary commitment computations that leave no retained candidate, custom root helpers and broader proof intent remain outside this restricted rule. Missing required observations and exhausted budgets are incomplete, never a quiet completion. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line merkle-leaf-binding-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-leaf-binding-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # merkle-membership-not-enforced > Proof-related state changes lack an enforced relationship between the exact digest and trusted ledger roots. Canonical: https://nightshade.dicksonwu.xyz/rules/merkle-membership-not-enforced.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `merkle-membership-not-enforced` | | Severity | medium | | Confidence | low | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | merkle-observations, successful-predicates, private-provenance, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors merkle-membership-not-enforced ./.nightshade/node_modules/.bin/nightshade detector show merkle-membership-not-enforced ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. Computing and checking a Merkle root does not enforce membership when the boolean result is discarded. Full example: https://nightshade.dicksonwu.xyz/examples.md#merkle-membership-not-enforced ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); tree.checkRoot(disclose(digest)); accepted = disclose(proof.leaf); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Proof-related effect lacks enforced trusted-root membership [merkle-membership-not-enforced] vulnerable.compact:7:18 7 | const digest = merkleTreePathRoot<2,Field>(proof); | ^ accept has a modeled successful history where proof-related data influences accepted, without a required check of that digest against definite preexisting ledger root data. Computing or ignoring a membership result does not enforce it. Review whether this effect requires membership; public deposits and root-management flows may be intentional. Source: vulnerable.compact:7:18 Call path: accept → merkleTreePathRoot Remediation: If membership is required, constrain successful execution with the exact digest's ledger-tree checkRoot result or equality with the intended trusted root. Preserve valid alternate checks and intentional public behavior. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Assert the result of checkRoot. ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); assert(tree.checkRoot(disclose(digest)), "member"); accepted = disclose(proof.leaf); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 5/5 | 5/5 | 5/5 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-membership-not-enforced.md at v0.1.1. Availability: **default**; no policy required. Severity **medium**, confidence **low**. Owned example: the compiler-qualified [fixture](#example-1) discards a root-check result before storing proof-dependent data. The [correction](#example-2) asserts that exact digest's check. Review a write that is intended to require tree membership; recommendation: enforce the relationship to the trusted preexisting root on every successful relevant history. A default-enabled **medium severity, low confidence** structural review rule. It reports a successful history where proof-related data influences persistent state or a canonical token operation without enforcing that exact digest's relationship to a preexisting ledger root. Whether membership is intended needs application review; this does not establish an authorization defect or exploitability. For example, this produces a review finding: ```compact const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); tree.checkRoot(disclose(digest)); accepted = disclose(proof.leaf); ``` When membership is required, constrain successful execution: ```compact assert(tree.checkRoot(disclose(digest)), "member"); accepted = disclose(proof.leaf); ``` A missing constraint can leave a state-changing operation independent of the intended tree membership. A check of a different digest, an ignored Boolean or an equality with a newly self-written root does not establish this relationship. The severity reflects the potential state/token effect; low confidence reflects unknown application intent and bounded abstract feasibility. The candidate must be a canonical computed root or private supplied `MerkleTreeDigest`, including nested wrapper/parameter fields, whose data or control dependencies reach a persistent write or canonical mint/send operation. Computed roots retain dependencies on the full path, including private nodes with a public leaf. Auxiliary path nodes do not independently become supplied-root candidates. Constructors, digest-only helpers and namesake user functions/types are outside this rule. An arbitrary Field witness is not presumed to be a digest. Dependencies also follow a required same-type equality of an exact private input before the effect. A separately supplied output constrained to equal a proof-related commitment's hash can therefore retain that relationship when it is stored. Sharing flow origins, wildcard storage addresses or witness declarations does not establish equality. Derived identities and cross-type comparisons do not identify a private input. Late equality cannot create an earlier dependency; late atomic root checks are assessed separately. This closure and every supplied digest candidate consume the existing matching allowance; exhaustion exposes no partial findings. Each immutable history decodes equality once; each effect visits only reachable dependency edges, filtering both write and operation positions. Histories without native operations retain ordinary flow provenance without new equality inference. Missing nonzero operation positions remain incomplete. Accepted evidence is a required positive result of the exact digest's check against a definite preexisting ledger tree, or transitive required equality with definite preexisting ledger root data. Query observations preserve their receiver snapshot, so dynamic-key checks and saved Booleans work without equating may-alias regions. Alternate checks, Boolean aliases, checks later in an atomic circuit, repeated computations and nested calls are supported. A prior required check stays valid after a later write. A check first made after insertion/reset does not establish membership in the original tree; equality with a retained original root can. Proof-identity traversal, predicate decoding, observation matching and path/effect storage have explicit bounds. Missing evidence or exhaustion emits an incomplete diagnostic. Detector-query exhaustion discards all partial findings for this rule. Caller summaries are interpreted while Merkle observations are requested because existing caller summaries do not replay these observations; leaf summaries remain available. This does not expand correlated-engine admission or default budgets. Some state updates intentionally do not require tree membership. The rule reports only the documented structural relationship and cannot infer whether the application requires membership, prove a feasible bypass, or establish deployed impact. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/merkle-membership-not-enforced.compact`). ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); tree.checkRoot(disclose(digest)); accepted = disclose(proof.leaf); } ``` #### Example 2 Correction (source: `tests/corpus/safe/merkle-membership-not-enforced.compact`). ```compact import CompactStandardLibrary; ledger tree: MerkleTree<2,Field>; export ledger accepted: Field; witness suppliedPath(): MerkleTreePath<2,Field>; export circuit accept(): [] { const proof = suppliedPath(); const digest = merkleTreePathRoot<2,Field>(proof); assert(tree.checkRoot(disclose(digest)), "member"); accepted = disclose(proof.leaf); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line merkle-membership-not-enforced -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-membership-not-enforced.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#merkle-membership-not-enforced) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # missing-role-bootstrap > An authenticated ShieldedAccessControl instance initializes but has no role-seeding route. Canonical: https://nightshade.dicksonwu.xyz/rules/missing-role-bootstrap.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `missing-role-bootstrap` | | Severity | low | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, module-identities, constructor-histories | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors missing-role-bootstrap ./.nightshade/node_modules/.bin/nightshade detector show missing-role-bootstrap ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/missing-role-bootstrap.md at v0.1.1. Availability: default-on; low severity, high confidence. Reports an authenticated ShieldedAccessControl instance that initializes in every successful constructor history but has no entry-reachable route to seed any role. With an empty role tree, guarded `grantRole` cannot establish the first role holder. ### Example and scenario ```compact import "access/ShieldedAccessControl" prefix SAC_; constructor(salt: Bytes<32>) { SAC_initialize(salt); } export circuit grant(role: SAC_RoleIdentifier, account: SAC_AccountIdentifier): [] { SAC_grantRole(role, account); } ``` Initialization stores state and salt; it does not insert an initial role holder. The library's documented constructor calls `_grantRole` separately. ### Recommendation Seed an initial role holder, usually `DEFAULT_ADMIN_ROLE`, with `_grantRole` during construction. Custom seeded roles and deliberate delayed setup are valid alternatives. Review the intended administrator relationships separately. ### Evidence and known false positives Requires compiler profile `compact-0.34.0-zkir2`, exact ShieldedAccessControl and Utils source bytes from compact-contracts revision `ec1331cd8195694c747d291e8fc8ab6d2914a976`, and complete successful constructor histories containing the canonical initialization write. The rule stops at the authenticated guarded `grantRole` boundary. Any other reachable raw `_grantRole` call or application reference to that instance's storage withholds the absence claim, even in dead source branches, zero-iteration loops and captured callback bodies. This check walks owned source statements rather than the pruned CFG. The upstream test mock deliberately exposes delayed bootstrap and remains quiet. Modified libraries and namesakes are outside this rule's identity scope. This rule does not assess seed adequacy, custom libraries, arbitrary access policies, missing initialization, or whether off-chain deployment procedures correctly perform a deliberately exposed setup operation. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line missing-role-bootstrap -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/missing-role-bootstrap.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # predictable-commitment-randomness > A published private-derived commitment uses statically known randomness. Canonical: https://nightshade.dicksonwu.xyz/rules/predictable-commitment-randomness.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `predictable-commitment-randomness` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | private-provenance, commitments, public-sinks, constants | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors predictable-commitment-randomness ./.nightshade/node_modules/.bin/nightshade detector show predictable-commitment-randomness ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. Publishing a commitment with fixed randomness can expose a small private input domain to guessing. Full example: https://nightshade.dicksonwu.xyz/examples.md#predictable-commitment-randomness ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; export circuit publish(): [] { published = persistentCommit(secret(), pad(32, "")); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Public commitment uses predictable randomness [predictable-commitment-randomness] vulnerable.compact:6:3 6 | published = persistentCommit(secret(), pad(32, "")); | ^ persistentCommit commits private-derived input using statically known randomness, and its result influences ledger-write published. This removes the protection supplied by secret, unpredictable commitment randomness; low-entropy inputs can remain guessable. Intentional deterministic commitments require review. Source: vulnerable.compact:6:15 Call path: publish Remediation: Use independently generated, sufficiently entropic private randomness appropriate to the primitive and protocol. Do not replace intentional deterministic protocol commitments without reviewing compatibility. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Take commitment randomness from a witness instead of a constant. ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; witness randomness(): Bytes<32>; export circuit publish(): [] { published = persistentCommit(secret(), randomness()); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/predictable-commitment-randomness.md at v0.1.1. Availability: **default**; no policy required. Severity **medium**, confidence **high** for the stated constant-randomness observation. Reports a tracked commitment of private-derived input influencing a public sink when every modeled component of its randomness is constant. This removes the protection supplied by secret, unpredictable commitment randomness. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) publishes a `persistentCommit` using a fixed byte string as randomness. The [correction](#example-2) supplies a separate witness value: ```compact published = persistentCommit(secret(), randomness()); ``` Review how a private value's commitment obtains its randomness, particularly when the value has a small set of possible inputs. Recommendation: use independently generated private randomness with entropy appropriate to the primitive and protocol. Review protocol compatibility before changing intentional deterministic commitments. ### False positives and limitations Deterministic protocols can match intentionally. The authenticated pinned standard-library `tokenType` declaration uses public domain-separated token derivation and is excluded; user-defined namesakes are still checked. Unknown witness randomness is not proven unpredictable, independent or sufficiently entropic. The rule is a constant-only check, not an entropy estimator or a proof of concrete feasibility or exploitability. Incomplete analysis is not a clean result. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/predictable-randomness.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; export circuit publish(): [] { published = persistentCommit(secret(), pad(32, "")); } ``` #### Example 2 Correction (source: `tests/corpus/safe/predictable-randomness.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger published: Bytes<32>; witness secret(): Field; witness randomness(): Bytes<32>; export circuit publish(): [] { published = persistentCommit(secret(), randomness()); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line predictable-commitment-randomness -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/predictable-commitment-randomness.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#predictable-commitment-randomness) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # public-key-membership-authorization > A raw native ownPublicKey selects a required member of preexisting public ledger storage before successful state-changing effects. Canonical: https://nightshade.dicksonwu.xyz/rules/public-key-membership-authorization.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `public-key-membership-authorization` | | Severity | high | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | collection-observations, successful-predicates, successful-histories, private-provenance, state-writes, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors public-key-membership-authorization ./.nightshade/node_modules/.bin/nightshade detector show public-key-membership-authorization ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 9/9 | 6/6 | 6/6 | 3/3 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/public-key-membership-authorization.md at v0.1.1. Availability: **default-on**, no policy required. Severity/confidence: **high/high**. This is a static trust-boundary review candidate. `soleGate` stays **unproven**; authentication intent, concrete path feasibility and deployed exploitability are not established. Select this rule alone with `--detectors public-key-membership-authorization`. The rule reports a raw canonical native `ownPublicKey` used as the active key of a required public Map/Set membership query on every modeled successful reach of an affected effect invocation. Membership in public identity storage does not establish possession of a secret. Other protocol checks can still apply. Findings group the enforcing predicate site and exported entry, list affected ledger/kernel effect invocations and preserve each matching history's immutable receiver/key, ledger revision, native witness invocation and actual effect positions. The first boundary is deliberately small: - Exact completed entry histories under `equivalent-states`, with all predicates and existing collection observations. Constructor setup is excluded. - Canonical `intrinsic::ownPublicKey`, with one exact raw native leaf. Keys may be the native `ZswapCoinPublicKey`, its unchanged `Bytes<32>` payload or canonical `Either` with a known active public-key arm and a default inactive contract-address payload. - A definite preexisting ledger receiver, no preceding ledger writes (`writesBefore === 0`), an unchanged receiver/query revision, and an exact immutable collection address. Wildcard regions do not establish equality. - The exact query-result identity must be required true on that same history. Direct assertion/branch polarity, negation and literal Boolean comparison are supported. Arbitrary Boolean equalities or compound/unknown encodings are not inferred. Optional, bypassed, ignored and negative membership stay quiet. - Query evaluation must precede its enforcing predicate. The predicate must precede each affected write or kernel operation by its recorded write/operation positions. Every successful reach of the exact effect invocation is intersected before source grouping. Different histories are never merged into one gate. Arbitrary user witnesses, entry-selected retrieval/payment identities, namesakes, private-secret hash identities, transformed native keys, inactive Either payloads, and general lookup-only membership are outside this rule. A supported raw native membership guard can still be intentional public-identity validation; review the protocol role. The rule does not establish intended privilege, secrecy/entropy, replay safety or a sole authentication gate. Guards after effects and receivers queried after ledger writes remain outside this first release. Exact observations use the existing entry-isolated rule pass and original 40,000-step/256-path/50,000-value limits; entries share the rule's value allowance. Consumer matching/intersection is bounded to 1,000,000 checks, with immutable operand/address traversals limited to 4,096 nodes and depth 32 and Boolean decoding to depth 64. Exhaustion or missing required invocation evidence produces rule/entry-scoped incomplete diagnostics and discards that entry's partial findings. Baseline completion and existing detector findings are preserved. Acceptance includes optional/bypassed branches, distinct calls/keys/receivers, changed current storage, nested summary replay, inactive/custom encodings, operation chronology, scoped budgets and instruction/reference × cached/uncached agreement. The detector analyzes source evidence; it does not run a witness, runtime, proof, transaction or exploit reproduction. Direct facts consumers also use the bounded structural Map/Set applicability check before requiring observations. Definite absence creates no missing-evidence error; an exhausted check remains incomplete. This preserves existing List-only registry consumers without weakening evidence for applicable contracts. The existing closed terminal-Counter grammar excludes witness calls, including natives; its experimental scan reuses that `no-witnesses` absence certificate. Other shapes still fall back to exact analysis; no Counter grammar or budget is broadened. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line public-key-membership-authorization -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/public-key-membership-authorization.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # publicly-derivable-encryption-secret > A published digest determines the scalar of a registered curve point through resolved native calls. Canonical: https://nightshade.dicksonwu.xyz/rules/publicly-derivable-encryption-secret.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `publicly-derivable-encryption-secret` | | Severity | high | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-calls, private-provenance, public-sinks, direct-hash-inputs, exact-invocation-operands | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors publicly-derivable-encryption-secret ./.nightshade/node_modules/.bin/nightshade detector show publicly-derivable-encryption-secret ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/publicly-derivable-encryption-secret.md at v0.1.1. Availability: default-on, **high severity / high confidence in the structural relationship**. Select with `--detectors publicly-derivable-encryption-secret`. ### Description A public digest can also determine the scalar used for a registered curve point. If the application treats that point as an encryption key, review whether its scalar was intended to remain private. The finding proves the modeled derivation relationship; it does not establish encryption use or application intent. ### Example An owned synthetic derivation: ```compact pure circuit makePoint(seed: Bytes<32>): JubjubPoint { const digest = persistentHash>>([seed]); return ecMulGenerator(degradeToTransient(digest)); } export circuit register(): [] { const seed = keyMaterial(); accountId = disclose(persistentHash>>([seed])); registeredPoint = disclose(makePoint(seed)); } ``` The published digest supplies the same `degradeToTransient` input used in the point derivation. Separating hash domains or using independent secret material breaks this exact relationship. ### Scenario and evidence The rule checks canonical resolved native calls, typed operands and straight-line helper bodies, including immutable local aliases. Provider names, source notices, commits and file fingerprints confer no role. The supported boundary is compiler 0.31.1, language 0.23.0 and ZKIR2 with its Field-based curve APIs. Different native profiles, unavailable recipe proofs and exhausted applicability budgets produce rule-scoped incomplete coverage when reached. A finding also requires the same exact immutable raw witness operand, a public `persistentHash>>` digest in an on-chain sink, an observed successful derivation invocation, and its exact result as the last whole-root `JubjubPoint` ledger write on one complete modeled outcome. Invocation arguments and results are recorded separately. Provenance sets, declaration names, flow strings and wildcard storage addresses never prove equality. Last-write checking rejects overwritten registrations. Committed checkpoint prefixes are separate outcomes. An impossible entire proof supplies no successful prefix. The optional observations retain the baseline engine and original budgets; missing invocation/digest evidence is explicitly incomplete. ### Recommendation Separate public-identifier and private-key hash domains, or use independent secret material. Confirm whether the registered point is a cryptographic key before treating the structural finding as a vulnerability. ### Known false positives and limits An intentionally public scalar or a curve point used for another purpose can match. Encryption/ciphertext use, intended secrecy and exploitability are not proven. Conditional/loop derivation bodies, arbitrary curve arithmetic, transformed seeds, Map/struct registrations and cross-entry key lifecycles are outside this proof boundary. Unknown reached recipe bodies are incomplete, not certified safe. Independent witness invocations, different hash types/domains, discarded points, exported-return-only digests and known constant-point derivations are quiet. ### Validation Owned compiler-valid positive, domain-separated and independent-secret controls exercise instruction/reference and cached/uncached evidence. Tests retain nested and repeated calls, caller guards, state invalidation, checkpoint prefixes, exact typed hash distinctions and explicit resource failures. These checks do not establish independent application recall. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line publicly-derivable-encryption-secret -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/publicly-derivable-encryption-secret.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # redundant-boolean-branch > Both branch arms only return opposite Boolean literals. Canonical: https://nightshade.dicksonwu.xyz/rules/redundant-boolean-branch.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `redundant-boolean-branch` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors redundant-boolean-branch ./.nightshade/node_modules/.bin/nightshade detector show redundant-boolean-branch ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/redundant-boolean-branch.md at v0.1.1. Availability: **default-on**, severity **info**, confidence **high**. The rule identifies an `if` with explicit `else` whose arms contain only opposite Boolean literal returns. Disclosure and identity casts of the literals, and single-statement nested blocks, preserve that shape. Conditions reduced to source constants and statements after definite rejection stay quiet. Physical generic claims must agree across every materialized instance. ### Example and scenario ```compact export circuit belowLimit(limit: Uint<64>): Boolean { if (disclose(round < limit)) { return true; } else { return false; } } ``` This view can express its predicate directly with `return disclose(round < limit);`. Inverse literal returns suggest the negated predicate. The condition, its effects and its disclosure boundary still matter. ### Recommendation and limits Consider a direct predicate return when it improves readability. Intentional explanatory branches can be retained. The rule describes source structure; it does not claim a security defect, reduced proof cost or compiler equivalence for an arbitrary rewrite. Validate a proposed rewrite with the project's compiler. Any additional branch statement, computed result, equal literal returns, sequence result or missing explicit `else` is excluded. This does not implement general Boolean optimization or arithmetic algorithm replacement. It addresses only the literal-return branch class, without analyzing deployed contracts. ### Evidence and known false positives Typed controls preserve condition effects/constraints across instruction/reference engines and cached/uncached modes. Compiler-valid source examples support the observation; intentional readability choices are factually matching informational reviews. Work/depth exhaustion emits rule-scoped `source-observation-budget` and never certifies a clean result. Source facts do not prove successful execution or natural recall. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line redundant-boolean-branch -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/redundant-boolean-branch.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # redundant-self-shielded-receive > Exact self-addressed canonical returned coin is subsequently passed to receiveShielded. Canonical: https://nightshade.dicksonwu.xyz/rules/redundant-self-shielded-receive.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `redundant-self-shielded-receive` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | runtime-operations, selected-invocation-observations, canonical-mint-observations, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors redundant-self-shielded-receive ./.nightshade/node_modules/.bin/nightshade detector show redundant-self-shielded-receive ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/redundant-self-shielded-receive.md at v0.1.1. Availability: **default-on**; severity **info**, confidence **high** for the supported source fact. This rule reviews an exact returned coin from canonical `mintShieldedToken`, or `sendShielded` / `sendImmediateShielded` `.sent`, subsequently passed to canonical `receiveShielded` on one original modeled successful history. It requires a recipient with `is_left == false` whose right `ContractAddress.bytes` has the exact immutable identity of an observed `kernel.self().bytes`. ```compact const coin = mintShieldedToken(default>, 1, default>, right(kernel.self())); receiveShielded(coin); ``` The owned pinned standard library automatically invokes its receive claim for this recipient. Review removing the explicit receive of the same returned coin. Keeping an explicit call for API symmetry or source readability can be intentional; this rule reports the duplicate call sequence, not a second coin output or a security defect. This is a call-sequence fact: ledger rejection, security impact, application intent, attack and transaction feasibility are not established. The helper compares represented coin components using immutable identities, constants and opaque mint-observation snapshots. Aliases and unchanged projections retain evidence; names, provenance unions and later predicate equalities do not identify coins. User namesakes are excluded by canonical identity. Change outputs, external recipients, independent recomputations, unknown recipient tags and predicate-linked recipient addresses are outside the supported shape. Mutually exclusive histories never donate a producer to a receipt. Later rejecting continuations contribute no successful history. Missing selected invocation or mint snapshot evidence and exhausted query allowances produce explicit rule-incomplete diagnostics. Reachable canonical `kernel.checkpoint()` entries are explicitly incomplete because the ordinary committed prefix observations lack exact returned invocation snapshots. The rule does not infer atomicity or discard checkpoint boundaries to claim completeness. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line redundant-self-shielded-receive -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/redundant-self-shielded-receive.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # spoofable-authorization > A raw witness equality with public data is required for a state-changing effect; review the intended authentication. Canonical: https://nightshade.dicksonwu.xyz/rules/spoofable-authorization.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `spoofable-authorization` | | Severity | low / high / critical | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | successful-predicates, private-provenance, state-writes, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors spoofable-authorization ./.nightshade/node_modules/.bin/nightshade detector show spoofable-authorization ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority; this rule assigns low, high, critical depending on the evidence. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. Comparing a caller-supplied public identity with the stored owner does not prove possession of its secret. Full example: https://nightshade.dicksonwu.xyz/examples.md#spoofable-authorization ```compact import CompactStandardLibrary; export ledger owner: ZswapCoinPublicKey; export ledger stored: Field; export circuit change(next: Field): [] { assert(ownPublicKey() == owner, "owner"); stored = disclose(next); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc HIGH — Public-key equality gates a state-changing effect [spoofable-authorization] vulnerable.compact:6:3 6 | assert(ownPublicKey() == owner, "owner"); | ^ change requires raw witness data from ownPublicKey to equal ledger owner on every modeled successful reach. The guard covers 1 effect site: ledger-write stored. Every successful history reaching these effects has only raw-witness/public-data checks; no additional modeled gate is present. Equality alone does not demonstrate possession of a secret; review the intended authentication and protocol role. Source: vulnerable.compact:6:10 Constraint: vulnerable.compact:6:3 Call path: change Remediation: If this check is intended as authentication, enforce a suitable secret-preimage or protocol-specific proof. Review key initialization, secrecy and replay assumptions. Document and triage intentional public-data validation. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Authorize with a private key preimage checked against the stored owner hash. ```compact import CompactStandardLibrary; export ledger owner: Bytes<32>; export ledger stored: Field; witness privateKey(): Bytes<32>; export circuit change(next: Field): [] { assert(persistentHash>(privateKey()) == owner, "secret preimage"); stored = disclose(next); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 28/28 | 28/28 | 28/28 | 0/0 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | known-bugs.json / authorization-raw-native-witness | positive | [7] to [6] | exact expectation mismatch | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/spoofable-authorization.md at v0.1.1. This default detector reviews exported circuits where a prover-supplied witness is required to equal a constant or public ledger value before a state-changing effect. Such an equality proves that the supplied value matches public data; it does not prove possession of a secret. Public-data validation can be intentional and still produce a finding. The detector follows required conditions across successful paths and groups affected effects by guard source and circuit. It preserves operand identity, branch polarity, call site, storage revision, and the guard's position relative to effects. A comparison that is computed but not enforced does not qualify. Identity-preserving copies and casts remain raw witness values; hashing a private preimage is a different relationship. Severity and confidence describe the structural evidence, not a conclusion about application intent. A sole modeled raw-witness or constant gate on a privileged effect can receive critical severity. Other privileged witness checks and public ledger key equalities receive high priority. Setup and nonprivileged validation remain low priority. A canonical receipt-coordination effect alone is classified as low-priority receipt validation; other affected effects in a mixed group are assessed separately. Circuit, ledger, and witness names are labeled heuristics, not proof of privilege or authentication intent. Signature-like witness names can raise review priority but cannot establish signature verification or support critical severity. For example, checking `identity() == owner` before changing state establishes only equality with the public `owner` value. If the protocol requires secret-key authorization, it should constrain a private preimage to trusted, preexisting owner data using the protocol's reviewed authentication construction. Review initialization, key handling, replay protection, and disclosure independently. Critical grading is deliberately conservative: every enforced condition must be a definite constant or a fully classified raw-witness comparison with public data. Additional private inputs, ledger conditions, ranges, collection predicates, checked conversions, arithmetic, lookups, or derived transaction operations prevent sole-gate certification. This test is sufficient evidence for a structural grade, not a general authentication proof. Private-preimage checks suppress the raw-equality finding only when they are required on every successful reach and bind the exact private input to trusted, preexisting ledger data. Self-written hashes, unrelated inputs, possible may-alias values, or a check present on only some paths do not establish that relationship. Public constraints on the preimage, entropy, later disclosure, and arbitrary signature or protocol authentication are outside the detector's proof. Unsupported rollback behavior and exhausted traversal or value budgets produce incomplete diagnostics; incomplete analysis does not establish absence of a finding. Aggregate conditions must be fully classified. Receipt-only findings describe receipt coordination and do not establish whole-transaction validity. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line spoofable-authorization -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/spoofable-authorization.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#spoofable-authorization) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-amount-set-consumption-review > Review exact surviving Set absence consumption before a zero-inclusive canonical unshielded payout. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-amount-set-consumption-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-amount-set-consumption-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Audit default | | Policy intent | not required | | Default enabled | yes | | Category | Audit-default ordinary rules | | Engine facts used | canonical-invocation-snapshots, collection-observations, all-predicates, exact-numeric-operands, completed-entries | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, so an ordinary scan runs it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-amount-set-consumption-review ./.nightshade/node_modules/.bin/nightshade detector show zero-amount-set-consumption-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 4/5 | 8/8 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / zeroAmountSetConsumptionReview40/drafts/consumption40/intentional-zero-consumption.compact | lookalike | [15] to [15] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-set-consumption-review.md at v0.1.1. Availability: default-on informational review. Requires complete ordinary histories with exact collection, invocation and numeric evidence; gaps remain explicit. This default informational rule reports a canonical unshielded send whose exact modeled amount retains zero, on the same ordinary successful history as an earlier required Set absence and exact-key insertion. The absence is enforced before insertion, its collection revision remains current until insertion, and that insertion survives through completion. Later removal or replacement followed by reinsertion cannot restore the earlier certificate. Resolved canonical calls and types select applicability. Immutable key and collection-address evidence establishes equality; names, shared wildcard storage paths and exclusive-branch effect unions do not. The rule reuses shared collection consumption and numeric transfers. Matching work is bounded; unavailable histories, operands and exhausted budgets diagnose incomplete analysis. Zero-value sends and Set consumption can be intentional protocol no-ops. The rule does not infer economic value or replay policy; review the purpose of the send and key before treating the observation as a defect. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-amount-set-consumption-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-set-consumption-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#audit-default-ordinary-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # always-true-assertion > Assertion is already true on every analyzed reach before enforcing it. Canonical: https://nightshade.dicksonwu.xyz/rules/always-true-assertion.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `always-true-assertion` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | assertion-reaches, completed-entries | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors always-true-assertion ./.nightshade/node_modules/.bin/nightshade detector show always-true-assertion ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/always-true-assertion.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for modeled pre-assertion truth. Use `--min-severity low` to hide informational findings, or `--detectors always-true-assertion` to select only this rule. Reports a root-file assertion already true on every modeled reach before that assertion adds a constraint. All reaching entries and potential callers must have complete analysis; unknown or uncovered reaches prevent a universal claim. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) uses self-equality for an intended counter-started check. Its [correction](#example-2) expresses that intended precondition: ```compact assert(round > 0, "counter started"); ``` Recommendation: check for a missing or mistaken operand, then restore the actual condition. Review earlier guards before removing a repeated assertion. ### False positives and limitations Defensive helper checks can be intentionally redundant after caller guards, and fixed inputs can make an assertion trivially true. High confidence describes the modeled observation, not a security defect or advice to delete the check. Assertions outside the root file are not reported. Unknown facts, incomplete callers and exhausted budgets cannot establish universal truth. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/always-true-assertion-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { assert(round == round, "counter started"); round.increment(1); } ``` #### Example 2 Correction (source: `tests/corpus/informational/always-true-assertion-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { assert(round > 0, "counter started"); round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line always-true-assertion -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/always-true-assertion.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # constant-condition > Branch condition reduces to a typed scalar source constant. Canonical: https://nightshade.dicksonwu.xyz/rules/constant-condition.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `constant-condition` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors constant-condition ./.nightshade/node_modules/.bin/nightshade detector show constant-condition ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/constant-condition.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the typed source-constant observation. Use `--min-severity low` to hide informational findings, or `--detectors constant-condition` to select only this rule. Reports a root-file branch condition reducing to the same typed scalar constant across its instantiated copies. This identifies a fixed branch choice for review. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) uses `if (1 < 2)` to select an increment. Its [correction](#example-2) keeps the selected `round.increment(1)` directly. Review accidental fixed operands when a branch was intended to depend on configuration or an input. Recommendation: verify the operands and intended configuration, then correct an unintended constant or simplify an intentional branch. ### False positives and limitations Compile-time configuration and generic specialization can intentionally fix a branch. The source model does not infer arbitrary call results or aggregate projections as constants; it is not a solver for all invariant conditions. Only root-file observations are reported. Budget exhaustion remains incomplete. [Dead-code](https://nightshade.dicksonwu.xyz/rules/dead-code.md) can separately report an excluded branch. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/constant-condition-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { if (1 < 2) { round.increment(1); } else { round.increment(2); } } ``` #### Example 2 Correction (source: `tests/corpus/informational/constant-condition-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line constant-condition -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/constant-condition.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # dead-code > Statement, branch or loop is excluded by source control flow. Canonical: https://nightshade.dicksonwu.xyz/rules/dead-code.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `dead-code` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors dead-code ./.nightshade/node_modules/.bin/nightshade detector show dead-code ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/dead-code.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the source-control-flow observation. Use `--min-severity low` to hide informational findings, or `--detectors dead-code` to select only this rule. Reports root-file statements after unconditional termination, branches excluded by typed scalar constants, and empty static loops. This is a bounded source observation rather than a general path-feasibility proof. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) places the update in `for (const i of 0..0)`, so it never executes. Its [correction](#example-2) performs `round.increment(1)` directly. Review the rule when expected work disappears after changing a range, a return, or a compile-time condition. Recommendation: correct the bound or control flow to restore intended execution, or remove intentional dead code after reviewing configuration variants. ### False positives and limitations Empty generic specializations and disabled configuration branches can be intentional. Arbitrary call results, aggregate projections and general relational infeasibility are outside the source constant model. Root-file scope does not certify imported code. Source traversal budget exhaustion remains incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/dead-code-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { for (const i of 0..0) { round.increment(1); } } ``` #### Example 2 Correction (source: `tests/corpus/informational/dead-code-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line dead-code -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/dead-code.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # shadowing > Parameter or local binding hides an outer declaration. Canonical: https://nightshade.dicksonwu.xyz/rules/shadowing.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `shadowing` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors shadowing ./.nightshade/node_modules/.bin/nightshade detector show shadowing ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shadowing.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the resolved binding observation. Use `--min-severity low` to hide informational findings, or `--detectors shadowing` to select only this rule. Reports a root-file local or parameter whose name hides an outer binding. Resolved lexical scopes and imported aliases determine which binding is hidden. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) has a ledger `round` and a `read(round: Field)` parameter. The [correction](#example-2) makes the data source clearer: ```compact export circuit read(value: Field): Field { return value; } ``` Review same-named parameters near ledger access or authorization helpers where a reader might mistake a caller-supplied value for state. Recommendation: give the inner binding a distinct name and check that each reference resolves to the intended declaration. ### False positives and limitations Constructor/API parameter names and small local scopes often shadow intentionally. The finding establishes a naming relationship, not incorrect binding, a security defect or a required rename. Only root-file observations are reported. Exhausted source traversal remains incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/shadowing-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } export circuit read(round: Field): Field { return round; } ``` #### Example 2 Correction (source: `tests/corpus/informational/shadowing-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } export circuit read(value: Field): Field { return value; } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line shadowing -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shadowing.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # time-dependence > A successful circuit uses a protocol block-time comparison. Canonical: https://nightshade.dicksonwu.xyz/rules/time-dependence.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `time-dependence` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors time-dependence ./.nightshade/node_modules/.bin/nightshade detector show time-dependence ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/time-dependence.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for a canonical block-time observation. Use `--min-severity low` to hide informational findings, or `--detectors time-dependence` to select only this rule. Reports a canonical block-time kernel read on a successful history of a completely analyzed entry. Called libraries are included, with the application's call site used when available. User-defined namesakes do not establish a kernel read. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) adds `assert(blockTimeGt(0), "started")`. Its [correction](#example-2) restores a clock-independent increment. For an actual deadline or timelock, the time dependency is expected; review the boundary instead of removing it. Recommendation: check inclusivity, expiration behavior, liveness near the boundary and permitted clock variation. Protocol time is not a randomness source. ### False positives and limitations Normal deadlines and timelocks intentionally match. The observation does not prove unsafe timing, randomness quality, cross-transaction feasibility or exploitability. It covers modeled canonical `blockTimeLessThan` and `blockTimeGreaterThan` operations, not every custom notion of time. Incomplete entries and exhausted observation budgets remain incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/time-dependence-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { assert(blockTimeGt(0), "started"); round.increment(1); } ``` #### Example 2 Correction (source: `tests/corpus/informational/time-dependence-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line time-dependence -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/time-dependence.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unnecessary-disclose > Disclosure operand is already public in the source context. Canonical: https://nightshade.dicksonwu.xyz/rules/unnecessary-disclose.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unnecessary-disclose` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unnecessary-disclose ./.nightshade/node_modules/.bin/nightshade detector show unnecessary-disclose ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unnecessary-disclose.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the source-publicness observation. Use `--min-severity low` to hide informational findings, or `--detectors unnecessary-disclose` to select only this rule. Reports root-file `disclose` operands already known public from literals or direct ledger data in a public source control context. This is a readability review of redundant permission annotations. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) uses `round.increment(disclose(1))`. Its [correction](#example-2) uses `round.increment(1)`. Review excessive annotations that obscure the places where private values actually cross a disclosure boundary. Recommendation: remove a redundant annotation only after confirming that the compiler accepts the intended privacy boundary. ### False positives and limitations A uniform explicit-disclosure style is harmless and may be intentional. The rule is a conservative source observation, not a compiler privacy proof or a secret leak detector. Calls and uncertain source/control contexts do not acquire assumed publicness. Only root-file observations are reported; exhausted source traversal is incomplete. See [declared-secret-publication](https://nightshade.dicksonwu.xyz/rules/declared-secret-publication.md) for policy-based private dependencies. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/unnecessary-disclose-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(disclose(1)); } ``` #### Example 2 Correction (source: `tests/corpus/informational/unnecessary-disclose-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unnecessary-disclose -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unnecessary-disclose.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unused-declaration > Ledger, witness or private circuit has no reference in the compilation unit. Canonical: https://nightshade.dicksonwu.xyz/rules/unused-declaration.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unused-declaration` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Hygiene only | | Policy intent | not required | | Default enabled | yes | | Category | Additional hygiene rules | | Engine facts used | resolved-model, typed-source-constants | | Release | v0.1.1 | ## Selection and scope Not in the default profile. `--profile hygiene` adds it, or select it explicitly with `--detectors`. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unused-declaration ./.nightshade/node_modules/.bin/nightshade detector show unused-declaration ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unused-declaration.md at v0.1.1. Availability: **default-on**; no policy required. Severity **info**, confidence **high** for the source-reference observation. Use `--min-severity low` to hide informational findings, or `--detectors unused-declaration` to select only this rule. Reports a root-file ledger, witness or private circuit with no source reference in the compilation unit. Exported circuit APIs are exempt; a source reference does not have to execute to count as a use. ### Example and review scenario The compiler-0.34.0-qualified owned [Counter fixture](#example-1) adds `ledger stale: Field;` without a reference. Its [correction](#example-2) removes that declaration. Review unused state or helpers after an API refactor. Recommendation: remove stale declarations or restore their intended use after checking application and off-chain consumers. ### False positives and limitations ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Counter fixture (source: `tests/corpus/informational/unused-declaration-positive.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. ledger stale: Field; export circuit increment(): [] { round.increment(1); } ``` #### Example 2 Correction (source: `tests/corpus/informational/unused-declaration-corrected.compact`). ```compact // This file is part of midnightntwrk/example-counter. // Copyright (C) Midnight Foundation // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma language_version >= 0.20; import CompactStandardLibrary; // public state export ledger round: Counter; // Nightshade owned informational regression; adapted from example-counter. export circuit increment(): [] { round.increment(1); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unused-declaration -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unused-declaration.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#additional-hygiene-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # checkpoint-splits-atomic-update > A checkpoint splits a declared ordinary Cell co-update across atomic units. Canonical: https://nightshade.dicksonwu.xyz/rules/checkpoint-splits-atomic-update.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `checkpoint-splits-atomic-update` | | Severity | low | | Confidence | high | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | declared-atomic-update-group, complete-checkpoint-linkage, ordered-cell-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors checkpoint-splits-atomic-update ./.nightshade/node_modules/.bin/nightshade detector show checkpoint-splits-atomic-update ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/checkpoint-splits-atomic-update.md at v0.1.1. Availability: **opt-in**, with an explicit `atomicUpdates` application policy. Severity **low**, confidence **high** for the linked write-occurrence observation. Compact's canonical `kernel.checkpoint()` marks preceding execution as one atomic unit and allows partial transaction failures across that boundary. This rule reviews a declared group of ordinary Cell writes split across those units. The reference establishes checkpoint semantics; it is not an independent bug label or evidence that a particular application can fail its later segment. ### Example and review scenario ```compact import CompactStandardLibrary; export ledger primary: Field; export ledger mirror: Field; export circuit synchronize(value: Field): [] { primary = disclose(value); kernel.checkpoint(); mirror = disclose(value); } ``` ```json { "version": 1, "detectors": ["checkpoint-splits-atomic-update"], "policies": { "atomicUpdates": [{"circuit": "synchronize", "ledgers": ["primary", "mirror"]}] } } ``` On a completely analyzed full history that writes every selected field, the rule reports a linked checkpoint prefix which writes a nonempty proper subset. It also reports mixed final write occurrences: both fields may have been written before the boundary, while one receives another write afterward. Values can be equal; the evidence concerns write occurrences, not numerical inequality. An example can split related ordinary Cell updates around an explicit checkpoint. The corrected form writes both snapshots before the boundary. A lookalike writes both before the boundary and writes unrelated padding afterward. ### Recommendation and known intentional uses Place coupled writes in the same atomic segment. Intentional staged commits are normal: omit this policy when the application permits them. Review proof constraints, privacy and transaction ordering before refactoring. The group must resolve to two through sixteen distinct canonical ordinary Cells on an exported entry circuit. Native ledger ADTs are outside this policy. Projected field writes remain explicitly unavailable. An entry that never has a complete all-field co-update is outside this rule's matching contract; the policy does not require every entry invocation to write every field. The observer links each full proof history directly to its own prefixes before flat outcome deduplication, retaining repeated/helper/callback invocation sites. Alternative histories remain separate evidence routes; their effects are never combined to invent a co-update. Later immutable-input proof checks and saved pre-boundary ledger-read checks retain the existing proof projection. Unprovable continuations supply no prefix evidence. Namesakes and unreached boundaries do not count. Unsupported effects, incomplete baseline entries, unavailable or truncated links, unsupported observation modes and exhausted shared step/path/value allowances remain rule-scoped incomplete. The baseline and other rules retain their separate completion. No symbolic execution, cross-entry invariant proof, actual partial failure, permanent loss or deployed impact is established. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line checkpoint-splits-atomic-update -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/checkpoint-splits-atomic-update.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # circuit-work-budget > Expanded source-operation estimate exceeds an explicit circuit work budget. Canonical: https://nightshade.dicksonwu.xyz/rules/circuit-work-budget.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `circuit-work-budget` | | Severity | low | | Confidence | high | | Maturity | experimental | | Selection | Audit; needs policy | | Policy intent | required | | Default enabled | yes | | Category | Policy-dependent rules | | Engine facts used | cfg, resolved-calls, static-loop-bounds, work-policy | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, but it stays dormant until `policies` in nightshade.json declares the matching application intent. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors circuit-work-budget ./.nightshade/node_modules/.bin/nightshade detector show circuit-work-budget ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/circuit-work-budget.md at v0.1.1. Availability: **policy-required**; selected by default, but needs `policies.workBudgets`. Severity **low**, confidence **high** for the source estimate. Reports an expanded source-operation upper bound above a configured circuit budget. The estimate expands static loops and callee work and conservatively counts both branch alternatives. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) repeats a Counter update four times. Its explicit review threshold is: ```json { "workBudgets": [{ "circuit": "update", "maxUnits": 5 }] } ``` Place this object under `policies` in the [configuration](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md). The [correction](#example-2) contains one update. Use the rule to notice source-work growth beyond an agreed project limit. Recommendation: inspect repeated loop and callee work, then measure actual compiler/prover cost before optimizing or adjusting the budget. For an opt-in fixed threshold without policy, see [circuit-cost](https://nightshade.dicksonwu.xyz/rules/circuit-cost.md). ### False positives and limitations Intentional large circuits or conservative branch expansion can exceed a useful application budget. Units are not proof rows, optimized compiler cost, runtime, memory usage or prover time. A finding is not evidence of an attacker-controlled unbounded loop or denial of service. An unavailable finite estimate emits an incomplete diagnostic instead of passing the configured check. A configured threshold is a project review limit, not a performance guarantee. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/work-budget.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger count: Counter; export circuit update(): [] { for (const index of 0..4) { count += 1; } } ``` #### Example 2 Correction (source: `tests/corpus/safe/work-budget.compact`). ```compact pragma language_version >= 0.26.0; import CompactStandardLibrary; export ledger count: Counter; export circuit update(): [] { count += 1; } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line circuit-work-budget -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/circuit-work-budget.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # current-root-policy-mismatch > An explicitly selected membership guard lacks current-root evidence at enforcement time. Canonical: https://nightshade.dicksonwu.xyz/rules/current-root-policy-mismatch.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `current-root-policy-mismatch` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | declared-current-root-policy, all-successful-predicates, native-merkle-queries, ordered-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors current-root-policy-mismatch ./.nightshade/node_modules/.bin/nightshade detector show current-root-policy-mismatch ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/current-root-policy-mismatch.md at v0.1.1. Availability: **opt-in policy**. Severity/confidence: **medium/high**. Select with `--detectors current-root-policy-mismatch` and declare the application requirement: ```json {"version":1,"policies":{"currentRootMembership":[ {"circuit":"record","ledger":"permitted"} ]}} ``` The policy applies to positive native `checkRoot` predicates enforced on modeled successful histories of the selected exported circuit. It requires the checked root to be current **when that predicate is enforced**. The ledger selector is an unambiguous canonical ledger ID or name; all native Merkle receivers below that root are selected, including nested Maps. Helpers retain their actual invocation operands and sites. This policy does not infer freshness intent. Equivalent repeated queries list every candidate invocation; the report never silently identifies an unused call as the saved Boolean's exact occurrence. ```compact import CompactStandardLibrary; ledger permitted: HistoricMerkleTree<2,Field>; export ledger accepted: MerkleTreeDigest; export circuit record(root: MerkleTreeDigest): [] { assert(permitted.checkRoot(disclose(root)), "membership"); accepted = disclose(root); } ``` Historic trees accept previous roots. An application that promises latest-snapshot acknowledgment should use `MerkleTree`, or establish a recognized current-only invariant with `resetHistory`/`resetToDefault` and perform a fresh query. Query-time proof alone is insufficient: saving a positive check, inserting into its tree, then asserting the saved Boolean does not certify the tree at that guard. Ordered real writes are checked between query and enforcement. Exact sibling writes preserve certification; possible aliases and ancestor replacements remove it. No comparison between Merkle epochs and ledger revisions supplies a proof. Native current trees remain exclusive for dynamic receivers too. The diagnostic reports a missing guard-time certificate under the explicit policy. It does **not** establish that historical roots are actually stored, that an overlapping write changes the root, that a stale root is accepted at runtime, or that a modeled history is feasible. Intentional historical membership is a known policy-dependent review shape: leave this policy unset. Negative checks, mere optional queries, and tautologies do not become required positive membership. A true branch does enforce membership on its own successful history. Later-effect freshness is outside this contract: a fresh guard followed by an insertion is quiet even if an effect happens afterward. Missing membership guards are also outside this rule; see `merkle-membership-not-enforced`. Independently bound current roots and unmodeled application invariants can make a reported certificate gap intentional. Nonliteral Boolean equality chains, lost predicate structure, unavailable/checkpoint-projected positions and exhausted budgets give explicit rule/entry-scoped incomplete diagnostics, never clean policy results. Boolean-to-numeric encodings in enforced predicates are also explicitly unavailable; conversions cannot erase a native check into apparent clean absence. Opaque native digest/commitment relations involving observed check Booleans retain a loss marker and are unavailable too; hashing is not decoded as Boolean equality or positive membership evidence. No successful invocation supplies no complete guard evidence. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line current-root-policy-mismatch -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/current-root-policy-mismatch.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # declared-secret-publication > Policy-declared secret information reaches a public sink through an unapproved transformation. Canonical: https://nightshade.dicksonwu.xyz/rules/declared-secret-publication.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `declared-secret-publication` | | Severity | high | | Confidence | medium | | Maturity | experimental | | Selection | Audit; needs policy | | Policy intent | required | | Default enabled | yes | | Category | Policy-dependent rules | | Engine facts used | private-provenance, implicit-flows, public-sinks, privacy-policy | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, but it stays dormant until `policies` in nightshade.json declares the matching application intent. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors declared-secret-publication ./.nightshade/node_modules/.bin/nightshade detector show declared-secret-publication ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/declared-secret-publication.md at v0.1.1. Availability: **policy-required**; selected by default, but needs `policies.secrets`. Severity **high**, confidence **medium**. Reports a policy-selected witness or entry parameter influencing a real public sink in a form not approved by `allowedForms`. This includes implicit control dependencies. `disclose` does not remove the source dependency; exported returns cross the application-output boundary, while ledger sinks publish ledger data. Without `sinkKinds`, the policy covers every public sink kind. An optional nonempty selection scopes it to `ledger-write`, `exported-return`, `ledger-operation`, or `event`; `allowedForms` still applies within that selection. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) forwards `secret()` through a helper to a ledger write. Its policy is: ```json { "secrets": [{ "witness": "secret" }] } ``` Place this object under `policies` in the [configuration](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md). The [correction](#example-2) publishes a constant independent of the witness. Review this finding when an application's privacy contract says a witness or parameter must not affect public output. Recommendation: remove the public dependency, including private-controlled effects, or explicitly approve a transformation after reviewing the disclosure requirements. Entry-parameter policies use `circuit` and `parameter` selectors. For an exported-return policy, select `exported-return` in `sinkKinds`. This scopes the policy to application outputs while leaving other sink kinds outside that policy selection; it does not establish that those operations hide a source or that the entire contract is secure. ### False positives and limitations An outdated or overbroad secrecy policy can flag intentional disclosures. Forms `raw`, `derived`, `hash` and `commitment` classify tracked transformations; they are not hiding proofs. Broadly approving `derived` can conceal implicit flows. No secrecy intent is inferred without policy, and abstract successful paths do not prove concrete feasibility. Incomplete analysis cannot establish absence of leaks. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/declared-secret.compact`). ```compact pragma language_version >= 0.26.0; export ledger published: Field; witness secret(): Field; circuit forward(value: Field): Field { return value; } export circuit publish(): [] { published = disclose(forward(secret())); } ``` #### Example 2 Correction (source: `tests/corpus/safe/declared-secret.compact`). ```compact pragma language_version >= 0.26.0; export ledger published: Field; witness secret(): Field; circuit forward(value: Field): Field { return value; } export circuit publish(): [] { const unused = secret(); published = 0 as Field; } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line declared-secret-publication -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/declared-secret-publication.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # forbidden-state-transition > A scalar state write may cross a transition explicitly forbidden by policy. Canonical: https://nightshade.dicksonwu.xyz/rules/forbidden-state-transition.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `forbidden-state-transition` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Audit; needs policy | | Policy intent | required | | Default enabled | yes | | Category | Policy-dependent rules | | Engine facts used | successful-paths, state-writes, constant-constraints, transition-policy | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, but it stays dormant until `policies` in nightshade.json declares the matching application intent. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors forbidden-state-transition ./.nightshade/node_modules/.bin/nightshade detector show forbidden-state-transition ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/forbidden-state-transition.md at v0.1.1. Availability: **policy-required**; selected by default, but needs `policies.transitions`. Severity **medium**, confidence **medium**. Reports a scalar ledger write whose modeled prior-state constants/exclusions and next value do not exclude a forbidden transition. Policies support enum, Boolean and numeric state; `"to": "*"` forbids any mutation from the selected prior state. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) sets `phase` to `OPEN` without excluding `CLOSED`. Its policy is: ```json { "transitions": [{ "state": "phase", "from": "CLOSED", "to": "OPEN" }] } ``` Place this object under `policies` in the [configuration](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md). The [correction](#example-2) enforces: ```compact assert(phase != Phase.CLOSED, "terminal state"); phase = Phase.OPEN; ``` Recommendation: compare the reported write with the application's transition table and constrain the old state before mutation. Review terminal states and all writers, including helper-mediated writes. ### False positives and limitations Unknown prior or next values leave transitions possible; a report does not prove that the old state is reachable across transactions. Application invariants outside the modeled invocation can make a match intentional or infeasible. Aggregate/collection member transitions and general transaction sequences are outside this scalar rule. Policies provide the intended prohibition; findings do not infer it. Missing models and exhausted budgets remain incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/forbidden-transition.compact`). ```compact pragma language_version >= 0.26.0; export enum Phase { OPEN, CLOSED } export ledger phase: Phase; export circuit reopen(): [] { phase = Phase.OPEN; } ``` #### Example 2 Correction (source: `tests/corpus/safe/forbidden-transition.compact`). ```compact pragma language_version >= 0.26.0; export enum Phase { OPEN, CLOSED } export ledger phase: Phase; export circuit reopen(): [] { assert(phase != Phase.CLOSED, "terminal state"); phase = Phase.OPEN; } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line forbidden-state-transition -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/forbidden-state-transition.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # openzeppelin-preconditions > Opt-in documented preconditions of authenticated OpenZeppelin Compact modules. Canonical: https://nightshade.dicksonwu.xyz/rules/openzeppelin-preconditions.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `openzeppelin-preconditions` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Configured builtins | | Policy intent | required | | Default enabled | yes | | Category | Policy-dependent rules | | Engine facts used | resolved-calls, call-reaches, complete-caller-coverage, builtin-policy | | Release | v0.1.1 | ## Selection and scope Selected when configuration declares the supported OpenZeppelin builtins. An explicit `--detectors` selection must also include it. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors openzeppelin-preconditions ./.nightshade/node_modules/.bin/nightshade detector show openzeppelin-preconditions ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 6/6 | 6/6 | 6/6 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/openzeppelin-preconditions.md at v0.1.1. Availability: **opt-in built-in policies required** through `policies.builtins`. An explicit detector selection must also include `openzeppelin-preconditions`. Severity **medium**, confidence **high** for the documented precondition evidence. Checks authenticated OpenZeppelin Compact **0.4.0-alpha.3**, revision `ec1331cd8195694c747d291e8fc8ab6d2914a976`, including resolved dependency hashes. It reports universally rejecting application calls with library assertion evidence, Ownable initialization outside construction, and Initializable import composition contrary to its documented top-layer/single-importer restriction. ### Example and review scenario Enable any relevant names under `policies.builtins`: `openzeppelin-ownable`, `openzeppelin-access-control`, `openzeppelin-pausable`, or `openzeppelin-initializable`; see [configuration](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md). For example, pausing twice can make the second call universally reject. Review the matched library contract and fix ordering, arguments, or initialization and import placement. One valid ordering is: ```compact P__pause(); P__unpause(); ``` ### False positives and limitations ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line openzeppelin-preconditions -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/openzeppelin-preconditions.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # operation-intent-policy > A protected Cell mutation does not satisfy its declared complete operation-intent statement. Canonical: https://nightshade.dicksonwu.xyz/rules/operation-intent-policy.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `operation-intent-policy` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | declared-operation-intent, exact-signed-statement, registered-key, original-write-history, canonical-self, nonce-consumption | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors operation-intent-policy ./.nightshade/node_modules/.bin/nightshade detector show operation-intent-policy ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/operation-intent-policy.md at v0.1.1. Availability: **opt-in**, **explicit policy required**. Severity: **info**. Confidence: **high** for a represented application-policy mismatch; deployment impact and globally feasible execution are unproved. Configuration version 1 accepts this additive optional policy. Report version 1.6.0 retains its existing findings/metadata and rule-coverage shape; this rule adds no serialized top-level report fields or custom-facts capability. Select `operation-intent-policy` and declare `policies.operationIntent`. Each policy selects an exported circuit, ordinary scalar protected Cells, a `Bytes<32>` registered-controller commitment Cell, an unsigned nonce Cell, natural numeric operation/version strings, exact signed statement field names, and exact input bindings. Canonical `kernel.self()` is mandatory. Operation tags must be distinct for entries sharing controller and nonce. Selectors resolve to unique canonical symbols; a parameter selector resolves inside its entry. ```json { "operationIntent": [{ "circuit": "updateDocument", "ledgers": ["document"], "controllerCommitment": "controllerCommitment", "nonce": "authorizationNonce", "operation": "1", "version": "1", "statement": { "self": "selfAddress", "operation": "operation", "version": "version", "nonce": "nonce" }, "inputs": [{"field": "input", "parameter": "next", "writeValue": "document"}] }, { "circuit": "revokeDocument", "ledgers": ["document"], "controllerCommitment": "controllerCommitment", "nonce": "authorizationNonce", "operation": "2", "version": "1", "statement": { "self": "selfAddress", "operation": "operation", "version": "version", "nonce": "nonce" }, "inputs": [{"field": "input", "ledger": "document"}] }] } ``` `parameter` inputs require `writeValue` or explicit `context: true`. `writeValue` selects the protected Cell whose actual written scalar must equal that signed field and the declared entry parameter. `context: true` requires exact signing of the parameter without claiming that it is the protected written value. Required scalar equalities before the write can connect aliases. `ledger` inputs select immutable initial-entry snapshots and express signed state context; they do not stand in for a dynamic write operand. An unsigned dynamic protected value without a declared write binding is a mismatch. Constants and exact Field self-subtraction have no independent dynamic write value. Ledger/local snapshots, shared source provenance and wildcard regions never donate must-equality. For each complete original successful effect history, one enforced canonical `secp256k1EcdsaVerify` result must cover the whole declared tuple before the write. Its actual `keccak256` input must have the declared fields. The exact verifier point must supply both canonical coordinates of the `persistentHash>` enforced equal to the preexisting registered commitment. Distinct witness calls do not imply equal keys. Signed tuple requirements cannot combine across separate signatures or exclusive histories. Mandatory scalar Boolean relays preserve equality/inequality parity and negation, including independently supplied outcomes: `v != relay` with `!relay` enforces the exact `v` as true, while the opposite relay truth enforces false. A separate bounded parity pass tracks these truth requirements without treating complement as scalar equality. Unanchored relays do not enforce true. Aggregate Boolean comparison projection, lost Boolean structure and conflicting parity evidence are scoped incomplete. Later checks remain outside the earlier effect's authorization prefix. Configured domain storage alone does not replace canonical self; version and current nonce are independent requirements. Native verifier semantics remain the compiler-profile model, not cryptographic protocol verification. Each successful selected operation with protected effects must have exactly one nonce write after all protected effects, with retained exact operands proving `currentNonce + 1` and a value-preserving unsigned result. Earlier nonce/controller writes, resets, repeated consumption, and controller enrollment in a selected mutation are mismatches. All exported callable closures are checked for other successful protected/controller/nonce writers; undeclared writers yield a scoped incomplete diagnostic. Constructors are the explicit enrollment/initialization boundary; trust in enrollment remains external. This rule does not establish nonce exhaustion behavior, trusted configuration, serialization injectivity or signature protocol security. Checked compiler arithmetic determines the modeled successful increment semantics. Preparation, interpretation, scalar closure, proof and retained evidence share 40,000 steps per entry, 256 paths and 50,000 cumulative abstract-value allocation units for the rule pass. These are the ordinary production limits, not extra proof budgets. Exact digest input and numeric operand evidence are opt-in and shared by both interpreter engines and cached/uncached transfers. The ordinary scan retains no operation-intent carrier, canonical-self marker or extra numeric operand metadata. Opaque statements/keys, lost identities, unsupported aliases, unresolved closures, baseline-incomplete entries, checkpoints requiring atomic linkage and exhausted budgets yield rule-scoped incomplete diagnostics. A false positive can reflect a stale, overbroad, or incorrect policy rather than a contract defect. Confirm that the declaration, signed fields, input bindings, and nonce expectations describe the application's intended protocol before acting on the finding. The rule checks conformance to configured policy; it does not infer that policy's correctness or prove signature security. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line operation-intent-policy -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/operation-intent-policy.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # source-claim-map-getter-review > An explicitly documented configured Map getter returns only default without reading the selected Map. Canonical: https://nightshade.dicksonwu.xyz/rules/source-claim-map-getter-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `source-claim-map-getter-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | explicit-source-map-getter-policy, parser-owned-adjacent-comment, complete-original-setter-getter-histories, complete-getter-source-closure | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors source-claim-map-getter-review ./.nightshade/node_modules/.bin/nightshade detector show source-claim-map-getter-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 4/4 | 2/2 | 2/2 | 10/10 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/source-claim-map-getter-review.md at v0.1.1. Availability: **opt-in**, **policy-required**; severity **info**. Select `--detectors source-claim-map-getter-review` and supply `policies.sourceMapGetters`: ```json { "sourceMapGetters": [{ "setter": "setAdmin", "getter": "getRoleAdmin", "map": "roleAdmin", "setterKey": "role", "setterValue": "admin", "getterKey": "role", "quote": "// Documentation claims DEFAULT_ADMIN_ROLE is customizable by roleAdmin entry." }] } ``` An outdated or overbroad documentation quote can produce an intentional policy mismatch. Verify that the quoted claim is current and that the setter/getter selectors reflect the actual API before changing code; the rule checks the configured claim and does not infer user expectations. This explicit contract says the getter should reflect the selected Map value configured by the setter for the same key. The analyzer does not infer this meaning from names or prose. Circuit/Map selectors resolve to unique active canonical symbols; parameter selectors are ordinary original names or canonical parameter IDs. Key and value types must agree exactly with the native Map and getter result, retaining nominal identities. Activation requires one complete parser-owned comment, including delimiters, exactly equal to the quote and immediately preceding the exported setter, with only whitespace between them. Removing the quote and the obsolete setter/Map is quiet. An exact quote remaining with missing or ambiguous setter identity is an invalid/incomplete observation. A different quote or nonadjacent comment is not-applicable. Existing `sourceClaims` policies retain their original semantics. A finding requires complete original successful setter histories with a surviving root-Map insertion of the selected original key/value operands, and complete getter histories returning the same exact default constant. The complete resolved getter source closure must have no read of this Map, including helpers, imports, lambdas and syntactically present zero-iteration callbacks. Unsupported external calls, unresolved effects, checkpoints, unavailable history identity or exhausted allowances produce rule-scoped incomplete diagnostics. Experimental Counter mode lacks the selected original setter/getter histories. Selecting this rule with a configured contract in that mode returns incomplete coverage and a diagnostic. Preparation, execution, matching and finding retention share the unchanged 40,000-step per-entry and 50,000-value cumulative rule allowance; histories are limited to 256. This source/API contract review does not execute a setter followed by a getter, infer cross-transaction feasibility, or establish deployed behavior or impact. Findings are informational and require the supplied contract. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line source-claim-map-getter-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/source-claim-map-getter-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # source-claim-shielded-issuance-review > Review an explicit adjacent source claim paired with shielded issuance to a user key. Canonical: https://nightshade.dicksonwu.xyz/rules/source-claim-shielded-issuance-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `source-claim-shielded-issuance-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | explicit-source-claim-policy, parser-owned-exact-adjacent-comment, canonical-mint-invocation, complete-original-successful-histories | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors source-claim-shielded-issuance-review ./.nightshade/node_modules/.bin/nightshade detector show source-claim-shielded-issuance-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 6/6 | 2/2 | 15/16 | 0/1 | 1 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / sourceClaims52/drafts/source-claims52/incomplete-unknown-tag.compact | negative | [] to [] | incomplete or unvalidated | | manifest.json / sourceClaims52/drafts/source-claims52/must-match-intentional-claim.compact | lookalike | [6] to [6] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/source-claim-shielded-issuance-review.md at v0.1.1. Availability: **opt-in**, **policy-required**; severity **info**. Select `--detectors source-claim-shielded-issuance-review` and configure an explicit policy: ```json { "sourceClaims": [{ "kind": "non-transferable-shielded-issuance", "circuit": "issue", "quote": "// Contract claim: recipients cannot transfer issued coins to other parties." }] } ``` A known benign mismatch is a policy quote that overstates transfer restrictions. It can yield an expected mismatch review. Confirm the claim's intended meaning and source location; the detector checks the supplied policy against represented code and does not infer broader transfer or deployment semantics. The policy supplies claim meaning. The analyzer does not interpret prose or infer intent from names, paths, omitted transfer circuits, or other source conventions. The selector must resolve uniquely to a canonical exported circuit. The quote must equal one complete parser-owned comment, including delimiters, in that circuit's declaration file immediately before the declaration, with only whitespace between the comment and declaration. Arbitrary exact quotes are supported when the policy explicitly supplies this claim kind. A finding pairs that comment with a canonical `mintShieldedToken` invocation on a complete modeled successful entry history whose fourth argument has exact native type `Either` and an active left (user-key) tag. Literal tags and mandatory final successful-history Boolean constraints supply evidence, including checks after the mint. Helpers, aliases and nonempty callbacks use ordinary call transfers. Aborted histories and zero-iteration callbacks do not contribute successful invocations. Compact **0.34.0/ZKIR2 or ZKIR3** is supported. Missing history evidence, opaque tags or layouts, unresolved calls, applicable unsupported profiles, checkpoints, unfinished baseline semantics and exhausted allowances produce incomplete rule-scoped diagnostics. Experimental Counter-query histories lack this rule's selected evidence and cannot certify a configured observation. Preparation, original-string UTF-8 adjacency inspection, capture, constraint matching and emission share **40,000 steps per entry, 256 paths per entry, and 50,000 cumulative values per rule**, with no retry. Default and unselected scans do not run this rule. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line source-claim-shielded-issuance-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/source-claim-shielded-issuance-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # stale-nft-metadata > Policy-selected current NFT metadata retains an old auxiliary payload across same-history burn/remint. Canonical: https://nightshade.dicksonwu.xyz/rules/stale-nft-metadata.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `stale-nft-metadata` | | Severity | low | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | module-identities, collection-observations, successful-histories, current-incarnation-policy | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors stale-nft-metadata ./.nightshade/node_modules/.bin/nightshade detector show stale-nft-metadata ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/stale-nft-metadata.md at v0.1.1. Availability: opt-in with an explicit `currentNftMetadata` policy; low severity, high confidence in the recorded preservation. Reports a separate application metadata cache that returns the exact payload stored before an authenticated same-ID NFT burn/remint on one complete modeled successful history. ### Intent and example Select this rule only when the cache serves the **current incarnation** of a token. Intentional archives must remain unconfigured. Names, URI contents and library imports do not establish this intent. ```json { "detectors": ["stale-nft-metadata"], "policies": { "currentNftMetadata": [ { "owners": "_owners", "metadata": "cachedURI", "consumer": "replaceToken" } ] } } ``` Selectors are unambiguous canonical declaration names or full symbol IDs. The ownership selector must identify the authenticated NFT instance's `_owners`. The separate cache must be a root `Map, Opaque<"string">>` and the consumer an exported circuit returning `Opaque<"string">`. ```compact NFT__mint(owner, tokenId); cachedURI.insert(disclose(tokenId), disclose(oldURI)); NFT__burn(tokenId); NFT__mint(owner, tokenId); return cachedURI.lookup(disclose(tokenId)); ``` Clear the auxiliary cache during burn, or supply the new incarnation's metadata before returning it. The pinned NFT already clears its own `_tokenURIs` on burn; this rule concerns the independently declared application cache. ### Evidence boundary This rule uses exact NonFungibleToken and Utils source bytes from compact-contracts revision `ec1331cd8195694c747d291e8fc8ab6d2914a976`, qualified for `compact-0.34.0-zkir2`. NFT SHA-256: `fe4d2b77a34d3f05a3b351d590ad55b2af5ca903c765bcd6946dceedbeecaed1`; Utils SHA-256: `215d6374bb22a7c950bb43d046f6380f2c432fb841a2fcead2a35766d159f314`. Modified providers and namesakes do not acquire the library's lifecycle identity. A configured relation against either reports a rule-scoped `nft-metadata-provider-unavailable` diagnostic and no NFT finding. An absent policy remains not applicable. Untrusted dependency bytes receive the same incomplete result; provider absence cannot certify a declared relation. Ordered collection operations and actual writes establish a cache insertion, canonical burn's zero-owner write, later canonical mint's owner write and final lookup, all for the same immutable token key and NFT instance. Returned scalar identity must equal the old inserted payload. Any later potentially overlapping cache mutation withholds preservation; any potentially overlapping owner write after remint also withholds it. Different dynamic keys can alias; distinct literal keys can be proved disjoint. Unknown keys never establish equality. Observation ordering has a deliberately narrow source boundary: the consumer's root block contains only expression/binding statements followed by a direct live cache lookup return. Its key is an effect-free reference, literal or default, optionally wrapped in casts or `disclose`. Saved reads, helper returns, effectful lookup keys and root control flow cannot establish this ordering. Unsupported terminal shapes, unknown relevant keys/values, custom ownership updates, transaction/context effects, unavailable exact observations, unqualified profiles and rule allowance exhaustion produce scoped incomplete diagnostics. Baseline and unrelated rule coverage remain independent. The observation helper marks its overall result incomplete when it emits any diagnostic, while retaining supported same-history observations even when another history for the same ownership/cache/consumer relation is unavailable. Diagnostics identify that relation in their message and are deduplicated by relation and code. Allowance exhaustion invalidates the entire bounded pass. The experimental Counter-query schema 1.2 does not run this isolated observation pass. An applicable configured NFT consumer therefore reports unavailable collection observations there; use the normal scanner for this rule. ### Remaining obligations ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line stale-nft-metadata -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/stale-nft-metadata.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unguarded-sensitive-state-write > A successful path writes policy-protected state without the configured preceding guard. Canonical: https://nightshade.dicksonwu.xyz/rules/unguarded-sensitive-state-write.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unguarded-sensitive-state-write` | | Severity | high | | Confidence | medium | | Maturity | experimental | | Selection | Audit; needs policy | | Policy intent | required | | Default enabled | yes | | Category | Policy-dependent rules | | Engine facts used | successful-paths, state-writes, guard-calls, authorization-policy | | Release | v0.1.1 | ## Selection and scope Selected by the default audit profile, but it stays dormant until `policies` in nightshade.json declares the matching application intent. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unguarded-sensitive-state-write ./.nightshade/node_modules/.bin/nightshade detector show unguarded-sensitive-state-write ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unguarded-sensitive-state-write.md at v0.1.1. Availability: **policy-required**; selected by default, but needs `policies.authorization`. Severity **high**, confidence **medium**. Reports a successful write to policy-protected ledger state without its required preceding successful void guard call. A write to a state dependency of that guard invalidates the earlier check. The configured requirement also applies to constructor writes. ### Example and review scenario The compiler-qualified owned [fixture](#example-1) has `publish` call a storage helper without its configured guard: ```json { "authorization": [{ "state": "published", "guard": "authorize" }] } ``` Place this object under `policies` in the [configuration](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/configuration.md). The [correction](#example-2) calls `authorize()` before `store(value)`. This supports review of a documented requirement shared by several entrypoints or helper paths. Recommendation: use a reviewed, constraining circuit returning `[]` before every protected mutation, and recheck after changing state that the guard reads. ### False positives and limitations The rule trusts the policy's guard meaning; it does not audit the guard or infer privilege from its name. A different check or a later atomic check can satisfy business intent while still violating the configured preceding-call requirement. An overbroad policy may therefore flag intentional behavior. A helper returning a witness Boolean alone is not the required successful void guard call. Abstract paths do not prove concrete feasibility or cross-transaction authorization. Unknown effects and exhausted budgets remain incomplete. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/required-guard.compact`). ```compact pragma language_version >= 0.26.0; export ledger allowed: Boolean; export ledger published: Field; circuit authorize(): [] { assert(allowed, "permission required"); } circuit store(value: Field): [] { published = disclose(value); } export circuit publish(value: Field): [] { store(value); } ``` #### Example 2 Correction (source: `tests/corpus/safe/required-guard.compact`). ```compact pragma language_version >= 0.26.0; export ledger allowed: Boolean; export ledger published: Field; circuit authorize(): [] { assert(allowed, "permission required"); } circuit store(value: Field): [] { published = disclose(value); } export circuit publish(value: Field): [] { authorize(); store(value); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unguarded-sensitive-state-write -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unguarded-sensitive-state-write.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unsupported-contract-owner > A declared callable pinned Ownable instance finishes with a contract-address owner rejected by its guard. Canonical: https://nightshade.dicksonwu.xyz/rules/unsupported-contract-owner.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unsupported-contract-owner` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | module-identities, state-writes, all-predicates, constants, completed-entries, callable-ownable-policy | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unsupported-contract-owner ./.nightshade/node_modules/.bin/nightshade detector show unsupported-contract-owner ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unsupported-contract-owner.md at v0.1.1. Availability: **opt-in policy**; severity **medium**, confidence **high** for the final selected tag and authenticated guard behavior. Concrete feasibility remains unproved. ### Description, example and scenario ```compact Ownable__unsafeTransferOwnership(right, ContractAddress>(next)); ``` For an owner selected by `callableOwnable`, a complete modeled successful history leaves the pinned Ownable owner's active arm as `ContractAddress`. Its `assertOnlyOwner` implementation explicitly rejects that arm, including nonzero contract addresses, while this owner value remains stored. The library's unsafe API is intentional; the policy declares that this particular owner guard must remain usable with the current implementation. Evidence uses OpenZeppelin Compact 0.4.0-alpha.3 revision `ec1331cd8195694c747d291e8fc8ab6d2914a976`, exact Ownable and Utils bytes, and the qualified Compact 0.34.0/ZKIR2 profile. The rule reviews configured application invariants; it does not claim an upstream defect or a newly confirmed vulnerability. ### Configuration and recommendation Select `unsupported-contract-owner` explicitly and declare: ```json { "callableOwnable": [{ "owner": "_owner" }] } ``` The selector must resolve to a root native `Either, ContractAddress>` ledger. Use its exact symbol ID when multiple instances make `_owner` ambiguous. Arrays must be dense and contain at most 64 owners; duplicate selectors for the same resolved owner are deduplicated. Authentication failures remain rule-scoped incomplete rather than quietly passing the declared obligation. Keep the selected owner in the account-identifier arm and use the safe ownership-transfer circuit. Intentional authority suspension, migration staging for future C2C support and test exposures should remain outside this policy. Declaring a policy without selecting this opt-in rule does not run the rule. ### Evidence and limitations Ordered state writes establish the final surviving discriminator for each selected instance and successful history. Whole-owner writes and aggregate reconstructions are compiler-qualified, including constructor and direct authenticated ledger assignments. Exact regional discriminator/payload facts are handled separately; their controls are synthetic because the pinned compiler rejects direct native Either field assignment. Payload-only mutations preserve the discriminator. A later left discriminator, safe replacement or canonical left/zero renunciation stays quiet. Rejected histories cannot supply a finding. Bounded successful-constant projection uses the same immutable snapshot and history, including later atomic assertions. It cannot borrow constraints from a different ledger revision, branch, wildcard region or module instance. Unknown final tags, unknown overlapping regions, absent invocation locations, incomplete entries, unsupported profiles and exhausted observations produce rule-scoped incomplete diagnostics. Supported findings for independent relations and histories remain available. The real-source seed triple is an owned focused mutation of the pinned OZ MockOwnable test wrapper. Its nonzero right owner is independent of the existing default-address rule; corrected and unrelated-ledger controls remain quiet. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unsupported-contract-owner -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unsupported-contract-owner.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-amount-initial-membership > Under a declared zero-amount policy, every modeled successful invocation requires the same Map entry to have been present initially. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-amount-initial-membership.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-amount-initial-membership` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in + policy | | Policy intent | required | | Default enabled | no | | Category | Policy-dependent rules | | Engine facts used | declared-zero-entry, exact-map-preconditions, all-successful-predicates, ordered-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json, and declare the matching application intent in `policies`. Selecting it alone does not supply that intent. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-amount-initial-membership ./.nightshade/node_modules/.bin/nightshade detector show zero-amount-initial-membership ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-initial-membership.md at v0.1.1. Availability: **opt-in policy**. Severity/confidence: **low/high**. Select with `--detectors zero-amount-initial-membership` and declare intended zero semantics: ```json {"version":1,"policies":{"zeroAmountMembership":[ {"circuit":"credit","amount":"amount","map":"balances"} ]}} ``` The rule reports when **every modeled full successful invocation of the selected entry, with its declared amount input fixed to zero, requires the same exact Map entry to have been present initially**. At least one modeled zero success is required. Other inputs and initial storage remain unknown. This is ordinary bounded abstract interpretation, with no solver, transaction execution or cross-transaction proof. The actual amounts passed to helpers retain their values: an entry-zero call can still pass `amount + 1` to a helper. ```compact export ledger balances: Map, Uint<64>>; export circuit credit(key: Bytes<32>, amount: Uint<64>): [] { const old = balances.lookup(disclose(key)); balances.insert(disclose(key), disclose((old + amount) as Uint<64>)); } ``` If zero operations must succeed without an existing balance/allowance entry, bypass lookup **and membership assertions** at zero, or supply the entry locally. A member assertion still requires initial membership. An optional `if (balances.member(key)) { ... }` is quiet when its absent route completes; prior insertion also supplies the entry and stays quiet. Intentional rejection is a known policy-dependent review shape; do not enable the policy for it. This diagnostic does not establish that an entry is missing in deployment, that any modeled history is concretely feasible, or that a runtime failure occurs. Only an exported circuit, scalar `Uint`/`Field` amount parameter and root Map ledger can be selected. Nested Map receivers have separate outer/inner atoms. Successful lookup preconditions are captured **before** membership refinement. Required saved member predicates retain their original query/write position. Ordered insertions, descendant value writes and known-empty receiver replacement are distinguished; wildcard keys, may-alias writes, unknown nested replacements, lost predicate structure and exhausted evidence remain explicitly unavailable. Reached checkpoints are unavailable because committed prefixes do not establish full entry success. No zero success normally supplies no clean rule result. One narrow exception certifies intentional rejection: an unconditional direct `Uint` amount comparison against zero fails with the exact declared input fixed to zero, while a separate complete ordinary analysis retains successful invocations. Both analyses share the step/value budgets, and the failed assertion remains in the evidence. Unrelated always-failing entries, contradictory guards, missing identity, reached checkpoints and exhausted evidence stay unavailable. The observation uses the existing budgets (40k steps/256 paths/50k values by default), including evidence traversal. Multiple declared inputs share entry work and the rule's value allowance. Storage summaries and compressed fold/hash/source histories are disabled until they can preserve these precondition snapshots. Both engines and cached/uncached modes have regression coverage. Rule failures remain rule/entry-scoped and do not change baseline default completion. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-amount-initial-membership -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-initial-membership.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#policy-dependent-rules) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # caller-supplied-time-review > Review an effect-bearing caller value checked against a ledger bound without a same-branch exact clock constraint; time intent unknown. Canonical: https://nightshade.dicksonwu.xyz/rules/caller-supplied-time-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `caller-supplied-time-review` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Time and freshness | | Engine facts used | resolved-model | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors caller-supplied-time-review ./.nightshade/node_modules/.bin/nightshade detector show caller-supplied-time-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks The 0.1.1 proof run had no mapped synthetic corpus checks for this rule, so there are no measured results to show here. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-time-review.md at v0.1.1. Availability: **opt-in** with `--detectors caller-supplied-time-review`; no policy required. Severity/confidence: **medium/low**. On a local exported-circuit branch with a ledger write or canonical send, flags an enforced comparison that places a caller `Uint<64>` above a ledger-derived bound without enforcing `blockTimeGte` or `blockTimeGt` on the same value. A `Uint<64>` need not represent time; independent review must establish that intent. Uses resolved identities, local aliases and separate branch states. It does not infer time from names, comments or strings. Direct calls are supported; helper-mediated constraints are outside this review. Unsupported loops and exhausted traversal budgets produce diagnostics. A caller-supplied numeric bound can be intentional, and the rule does not infer that the value represents a timestamp. Review the protocol's time source and same-branch guards before changing the circuit; this finding does not prove a feasible stale-time execution. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line caller-supplied-time-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-time-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#time-and-freshness) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # shielded-coin-runtime-width > A definite native shielded output exceeds the expressly assumed runtime coin encoding range. Canonical: https://nightshade.dicksonwu.xyz/rules/shielded-coin-runtime-width.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `shielded-coin-runtime-width` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Time and freshness | | Engine facts used | canonical-native-output-sites, exact-numeric-operands, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors shielded-coin-runtime-width ./.nightshade/node_modules/.bin/nightshade detector show shielded-coin-runtime-width ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-coin-runtime-width.md at v0.1.1. Availability: **opt-in reference-runtime compatibility review**, no policy required. Severity/confidence: **low/high**. Select with `--detectors shielded-coin-runtime-width`. A canonical native `createZswapOutput` receives a definite integer coin value of at least 18,446,744,073,709,551,616 on a modeled successful history. Compact 0.34.0 declares `ShieldedCoinInfo.value` as `Uint<128>`, while the pinned runtime 0.19.0 descriptor encodes eight bytes, with maximum 18,446,744,073,709,551,615. The finding expressly assumes that reference runtime. The analyzer does not discover or verify the project's installed or deployed runtime. ```compact import CompactStandardLibrary; export circuit output(): [] { const coin = ShieldedCoinInfo { nonce: pad(32, "nonce"), color: pad(32, "color"), value: 18446744073709551616 as Uint<128> }; createZswapOutput(coin, left( ZswapCoinPublicKey { bytes: pad(32, "recipient") })); } ``` Review runtime compatibility and constrain emitted values to its supported range, or use a separately qualified compatible runtime. This static diagnosis does not prove funding, proof feasibility, runtime rejection, asset loss or a deployed bug. An exact source match can be irrelevant to a project using a different runtime; this is a known benign match when the actual runtime supports a wider descriptor. Verify the project's runtime version before acting; this version-dependent applicability keeps the rule opt-in. The first supported profile is **Compact 0.34.0/ZKIR2 with expressly assumed runtime 0.19.0**. Relevant entries under other compiler/ZKIR profiles produce rule-scoped `runtime-width-profile-unavailable` diagnostics; structurally unrelated entries remain not applicable. Baseline-incomplete entries are withheld explicitly. JSON, SARIF and the human report distinguish baseline and selected-rule coverage. The experimental Counter-predicate scan has no certificate for this rule; missing exact quantity observations remain explicitly incomplete in that mode. The isolated quantity observation pass preserves exact native operands and immutable storage snapshots, with all successful predicates and equivalent-state histories. Legal aggregate widening may retain a narrower unsigned operand domain; it is accepted only when contained in Uint128, with integer constants checked against that retained domain. It disables numeric fold compression and retains the ordinary 40,000-step/256-path/50,000-value limits. Canonical source-site traversal and operand review are bounded; unavailable evidence yields incomplete diagnostics, with no partial findings for the affected entry. Independent completed entries remain available. Alternative paths at one output site are grouped with their amounts and invocation sites. Unknown quantities, inferred bounds, merely returned coin structs, arbitrary user namesakes, proof generation and runtime evaluation remain outside this contract. Quiet unknown quantities are not a general runtime-compatibility guarantee. False-positive pattern: a project using a runtime whose descriptor accepts a wider quantity may still match the documented reference-runtime boundary; verify the actual runtime version before acting. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line shielded-coin-runtime-width -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-coin-runtime-width.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#time-and-freshness) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # caller-key-zero-entry-review > Review a surviving zero numeric Map insertion at a direct caller key without required initial same-key membership. Canonical: https://nightshade.dicksonwu.xyz/rules/caller-key-zero-entry-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `caller-key-zero-entry-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | entry-zero-history, exact-map-preconditions, all-successful-predicates, ordered-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors caller-key-zero-entry-review ./.nightshade/node_modules/.bin/nightshade detector show caller-key-zero-entry-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-key-zero-entry-review.md at v0.1.1. Availability: **opt-in**; no policy required. Severity: **info**. Confidence: **high** for the supported static source relationship. Select with `--detectors caller-key-zero-entry-review`. The observer fixes an actual numeric entry parameter to zero and preserves other inputs and helper arguments. APIs inserting literal zero use complete ordinary histories and need no fabricated amount parameter. It reports a numeric `Map, ...>.insert` whose amount retains an unchanged entry-input identity or is literal zero, and whose key retains an unchanged entry-input identity, when the write survives a modeled full successful invocation without required initial membership at that exact key or an enforced finite literal key domain. One qualifying successful history suffices; other zero histories may perform no insertion. Required same-key initial membership excludes existing-only updates. Unrelated may-alias keys do not establish equal entries. Literal key domains, fixed-key writes, transformed amounts, positive guards, and writes later removed, reset or overwritten are quiet. A later overlapping write withholds survival evidence unless its exact ordered insert/remove operation addresses the same Map with an immutable key required distinct on that same successful history. Possible Boolean alternatives, wildcard addresses, ancestor resets and unproven aliases supply no disequality proof. Withheld survival evidence does not claim the write was necessarily removed. Exact collection/query revisions and ordered write positions are shared with `zero-amount-initial-membership`. Ordinary scans are unchanged. Missing exact facts, unqualified no-zero-success cases, reached checkpoints and exhausted budgets produce rule diagnostics. Direct nonzero entry guards are a narrow qualified rejection boundary; other zero-path failures remain unavailable. An API that intentionally creates a zero-valued entry can match. Review whether the application requires an existing key or a positive amount before treating the finding as a defect; the rule does not infer that policy. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line caller-key-zero-entry-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-key-zero-entry-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # closed-membership-capacity-review > A represented constructor history contradicts distinct Set memberships under a complete source closure without subsequent writers. Canonical: https://nightshade.dicksonwu.xyz/rules/closed-membership-capacity-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `closed-membership-capacity-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | constructor-to-entry-prefixes, exact-collection-capacity, complete-post-constructor-effects | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors closed-membership-capacity-review ./.nightshade/node_modules/.bin/nightshade detector show closed-membership-capacity-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 6/6 | 3/3 | 2/2 | 10/10 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/closed-membership-capacity-review.md at v0.1.1. Availability: **opt-in** with `--detectors closed-membership-capacity-review`; no policy required. Severity: **info**. This opt-in informational rule reports a represented constructor configuration whose current native Set capacity is smaller than the gate's mandatory, pairwise-distinct memberships. It also requires complete resolved source evidence that no post-constructor public callable can write that whole Set root. The source closure includes every public entry, its helpers, import instances and callbacks. Any insert, remove or other may-write to the root prevents this conservative certificate, including a writer callback over a zero-length vector. An unrelated ledger writer does not prevent certification of the target root. Unresolved callables, external contract calls, committed checkpoints and exhausted allowances produce scoped incomplete diagnostics. Nested collection receivers are outside this rule's whole-Set admission boundary. The existing `configured-membership-capacity-review` remains separate: its immediate constructor-state observation allows later configuration writers. The new rule retains its exact capacity, current-revision, immutable operand and mandatory pairwise-distinctness requirements. Wildcard regions, possible Boolean alternatives and unknown storage supply no cardinality proof. A deliberately fixed registry can match when the application intentionally makes some operations reject for lack of capacity. The finding describes only the represented constructor state and complete no-writer certificate; it does not establish deployment impact or later transaction feasibility. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line closed-membership-capacity-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/closed-membership-capacity-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # configured-membership-capacity-review > Immediate post-constructor collection capacity contradicts required distinct memberships. Canonical: https://nightshade.dicksonwu.xyz/rules/configured-membership-capacity-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `configured-membership-capacity-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | constructor-to-entry-prefixes, exact-collection-capacity, successful-predicates | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors configured-membership-capacity-review ./.nightshade/node_modules/.bin/nightshade detector show configured-membership-capacity-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 3/3 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/configured-membership-capacity-review.md at v0.1.1. Availability: **opt-in** with `--detectors configured-membership-capacity-review`. Severity: **info**. Confidence: **high** for the represented state/constraint contradiction. The independent observer invokes the constructor then a membership-bearing entry with fresh inputs and exact carried storage. It records assertion prefixes, including prefixes rejected by ordinary execution. Current collection capacity upper bounds and enforced pairwise key inequalities can prove that required memberships are inconsistent immediately after that represented construction. This does not establish permanent unusability, concrete invocation feasibility, or native cryptographic validity. Later enrollment or other configuration can change storage. No constructor or unknown entry storage supplies an empty-set assumption. The rule never promotes sequence failures to universal `impossible-assertion` findings. Only exact immutable receiver/key identities and required Boolean constraints participate. Wildcard address equality, stale saved membership results and unknown collection replacements provide no capacity proof. Missing evidence, unsupported relations/effects or exhausted budgets diagnose. Conservative upper-bound tracking is enabled only for this observation; ordinary collection snapshots and defaults remain unchanged. Unrelated entries receive resolved structural absence coverage; independent baseline gaps remain explicit. Ordinary registry dispatch stays inert without the optional constructor-boundary facts. Selected scans request the independent observer and retain its missing evidence and budget diagnostics. A policy that intentionally requires more distinct members than the configured capacity may produce this informational finding by design. Later configuration can change the result; the observation is not a permanent-usability proof or a claim that the constructor can be deployed or invoked successfully. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line configured-membership-capacity-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/configured-membership-capacity-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # enrolled-signature-key-review > Review unknown persistent Schnorr keys without modeled identity rejection. Canonical: https://nightshade.dicksonwu.xyz/rules/enrolled-signature-key-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `enrolled-signature-key-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | successful-signature-calls, all-predicates, original-write-history | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors enrolled-signature-key-review ./.nightshade/node_modules/.bin/nightshade detector show enrolled-signature-key-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/enrolled-signature-key-review.md at v0.1.1. Availability: **opt-in**; informational severity, medium confidence. No policy required. Review an unknown entry-storage snapshot from a whole persistent JubjubPoint Cell passed to the canonical pinned `jubjubSchnorrVerify`, when no modeled mandatory check on that exact successful history excludes the identity point. Enrollment validation in another transaction, trusted initialization or application policy may make this intentional. The rule does not establish unsafe enrollment, a known identity key, signature enforcement, sole authorization or exploitability. Ordinary aliases, helper arguments and retained snapshots preserve immutable identity. Guards on another key or a new storage revision do not protect an old snapshot. Mandatory equality constraints and both branch polarities stay within their original history; checks from mutually exclusive histories are not joined. An enforced `ecMul(key, scalar) != default` or `ecNeg(key) != default` excludes identity of that exact key because the pinned native operations map identity to identity. This inference says nothing about subgroup membership, curve membership or off-curve inputs. The pinned 0.35.0 and 0.35.0-rc.1 canonical verifiers reject identity internally; their successful calls are quiet. Direct caller or witness keys, transformed point keys, projected struct fields, collection values, same-named application circuits and known identity keys are outside this review. The existing `identity-signature-key` detector continues reporting its known identity evidence. Source unknowns and exhausted allowances produce explicit incomplete diagnostics. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line enrolled-signature-key-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/enrolled-signature-key-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # membership-identity-binding-review > Keyed mutation digest/key equality and required Set membership use independent witness snapshots. Canonical: https://nightshade.dicksonwu.xyz/rules/membership-identity-binding-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `membership-identity-binding-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | all-predicates, digest-inputs, collection-operations, original-write-history | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors membership-identity-binding-review ./.nightshade/node_modules/.bin/nightshade detector show membership-identity-binding-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 4/4 | 3/3 | 2/3 | 5/5 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / independentMembershipIdentity54/drafts/memo-identity44-boundaries/intentional-admin.compact | lookalike | [20] to [20] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/membership-identity-binding-review.md at v0.1.1. Availability: **opt-in** with `--detectors membership-identity-binding-review`. Findings are informational policy questions, with high confidence limited to the observed source relationship. The rule observes a canonical `Map, List>>` mutation at an exact key. Imported aliases and nominal container aliases are admitted only when canonical native identity and recursively resolved argument shapes agree. Required scalar equalities connect that key to a canonical `persistentHash` of one raw, declared `Bytes<32>` witness snapshot. A required canonical `Set>.member` predicate tests an independent raw witness snapshot in the same completed atomic history. No required scalar equality connects the digest or its input to the membership input. A public key parameter is not trusted ledger data; this equality alone does not establish authentication policy. One report groups a digest/key snapshot, membership predicate and nested Map root, retaining a representative mutation and the observed source sites. Different roots, membership snapshots and digest snapshots remain separate questions. Source sites can occur on different complete histories; their effects are never combined into a single executable history. Zero-iteration histories supply no mutation. Optional membership in an alternative successful history at the same mutation site suppresses the mandatory composition question. Required Boolean facts are intersected; exclusive checks never donate equality or membership. Direct, transitive, aliased and late atomic scalar equalities bind snapshots. Repeated invocations of one witness declaration remain independent. Equal hash outputs never establish equal preimages. Query identities retain the exact Set receiver, operand and ledger revision. Wildcard mutation paths cannot supply exact key evidence. Unavailable histories, predicate structure, snapshot identities, checkpoints and exhausted budgets produce diagnostics and incomplete coverage. The initial boundary excludes other represented container shapes, aggregate or transformed witness inputs, user collection lookalikes, and cross-entry policy comparison. Preparation, execution, additional collection retention, matching and report construction share 40,000 steps per entry, 256 paths per entry and 50,000 cumulative abstract values per selected rule; no retry budget applies. An application may intentionally use one supplied identity for a stored map key and an independent witness for membership. That source relationship is an informational review question, not proof of an authorization defect; confirm the intended identity-binding policy before changing it. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line membership-identity-binding-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/membership-identity-binding-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # native-key-authentication-review > Canonical prover-supplied ownPublicKey participates in a required ledger credential check. Canonical: https://nightshade.dicksonwu.xyz/rules/native-key-authentication-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `native-key-authentication-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | all-successful-predicates, direct-hash-inputs, exact-effect-histories | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors native-key-authentication-review ./.nightshade/node_modules/.bin/nightshade detector show native-key-authentication-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 5/5 | 5/5 | 5/5 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/native-key-authentication-review.md at v0.1.1. Availability: opt-in. Severity: info. Confidence: high. Opt-in candidate, informational severity and high confidence in the static source relationship. Canonical native `ownPublicKey` is prover supplied and does not separately establish control of the corresponding key. The rule observes a required exact equality to preexisting ledger data on completed successful effect histories, either with an independent mandatory private-preimage check or with the native key as an exact ingredient of a canonical hash/commit credential containing another private witness input. Other secret credentials can provide sufficient authentication. Legitimate intentional constructions can match. This observation establishes neither authentication intent, transaction feasibility, separate key control nor an authentication bypass. Direct raw native-key cases lacking a mandatory secret-preimage check remain covered by `spoofable-authorization`. Matching uses canonical native source identity and exact immutable input snapshots, never witness names or dependency unions. Optional/disjunctive checks, preview-only comparisons, unrelated key/secret predicates, self-written ledger credentials and wildcard selectors do not establish the required relationship. Unknown predicate/invocation evidence and exhausted observation allowances produce rule-scoped incompleteness. The closed terminal Counter grammar certifies absence because it excludes all witnesses. Commitment input/randomness snapshots use a dedicated observer flag. Ordinary digest observation supplies no commitment-evidence certificate; selecting this review enables it in the isolated rule pass. Missing applicable snapshots remain rule-scoped incomplete. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line native-key-authentication-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/native-key-authentication-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # quorum-signer-uniqueness-review > Adjacent signer inequalities omit non-adjacent pairs in a verified threshold claim vector. Canonical: https://nightshade.dicksonwu.xyz/rules/quorum-signer-uniqueness-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `quorum-signer-uniqueness-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | all-successful-predicates, exact-entry-operands, canonical-ecdsa-operands, collection-operations, direct-hash-inputs | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors quorum-signer-uniqueness-review ./.nightshade/node_modules/.bin/nightshade detector show quorum-signer-uniqueness-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/quorum-signer-uniqueness-review.md at v0.1.1. Availability: opt-in. Severity: info. Confidence: high in the static source relationship. The rule reviews directly presented entry-parameter vectors of 3..16 signer claims under the Compact 0.34.0 ZKIR3 profile. Each represented claim must contain one canonical ECDSA signature, one canonical Secp256k1 point and one Bytes<32> commitment. It requires the canonical ECDSA verifier outcome for every claim, a keccak256 message of that claim's commitment, a required equality binding the commitment to the persistent hash of its public key's exact native X/Y coordinates, and required membership of every commitment in the same preexisting Set revision. A required comparison checks the fixed presented count against a supplied Uint threshold. Within that complete successful history, adjacent scalar commitment inequalities are enforced and one or more non-adjacent inequalities are absent from the required scalar equality/inequality closure. Adjacent inequality alone does not establish pairwise uniqueness. The observation identifies the missing pairs; it does not establish that duplicates can satisfy other protocol checks, that the threshold is the sole authorization gate, or that a transaction or bypass is feasible. Independently established uniqueness can make a match intentional. Review whether the threshold counts distinct signers, and enforce the protocol's complete uniqueness condition if needed. Matching uses canonical call identities, represented entry operands, exact native digest inputs, registry revisions and required predicate snapshots. Application namesakes, ordinary sequences, two-claim vectors, unrequired verifier outcomes and complete pairwise inequality checks do not match. Aliases preserving supplied snapshots remain exact; shared wildcard storage regions and dependency unions cannot establish equality. A condition can be required in one successful branch history without being universal across the entry; findings make only that history's relationship claim. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line quorum-signer-uniqueness-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/quorum-signer-uniqueness-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # signature-key-identity-exclusion-review > Review unknown native signature keys without modeled exact identity exclusion. Canonical: https://nightshade.dicksonwu.xyz/rules/signature-key-identity-exclusion-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `signature-key-identity-exclusion-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | canonical-native-verifier-operands, complete-original-successful-histories, typed-immutable-key-exclusion | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors signature-key-identity-exclusion-review ./.nightshade/node_modules/.bin/nightshade detector show signature-key-identity-exclusion-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 2/5 | 1/1 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / signatureIdentityExclusion46/drafts/signature46/caller-key/lookalike.compact | lookalike | [5,9] to [5,9] | control hit | | manifest.json / signatureIdentityExclusion46/drafts/signature46/persistent-key/lookalike.compact | lookalike | [12,17] to [12,17] | control hit | | manifest.json / signatureIdentityExclusion46/drafts/signature46/counter/lookalike.compact | lookalike | [44,45] to [44,45] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/signature-key-identity-exclusion-review.md at v0.1.1. Availability: **opt-in**, informational severity, high confidence in the reported source relationship. No policy required. Review an unknown caller key or an unknown whole persistent Cell snapshot passed to the canonical native Jubjub Schnorr or secp256k1 ECDSA verifier. A finding says that a complete original modeled successful history contains no modeled mandatory caller or internal check excluding the identity of the exact immutable key on its own curve. Message-only checks retain the key obligation. An application namesake verifier is outside scope. This does not establish that the key is identity, that an identity input could satisfy the other checks, that enrollment is unsafe, or that a signature is mandatory. Curve membership, subgroup validity, sole authorization, concrete feasibility and application impact remain unproved. Trusted initialization or application policy can make the observation intentional. A check in a separate enrollment transaction cannot validate an unknown later storage snapshot without a complete storage invariant. The observer captures caller-refined arguments in evaluation order before the callee adds constraints, then retains the invocation only on its successful history. Imported aliases, ordinary helpers, callbacks and summary replay use the ordinary transfer engine. Empty callback sequences retain zero-iteration behavior. Exact key inequalities, mandatory equalities and native identity-to-identity `ecMul`/`ecNeg` observations are joined only within that history. An enforced nonidentity cofactor result excludes identity of that exact Jubjub input; it proves no curve or subgroup property. Native generator nonidentity is evidence about its output only. Coordinate checks or derived verifier points cannot validate an input key by inversion. Guards on another key, a different Cell revision or a mutually exclusive history cannot discharge the obligation. The supported exact profiles are Compact 0.34.0/ZKIR2 for Schnorr and 0.34.0/ZKIR3 for both families, plus 0.35.0 and 0.35.0-rc.1/ZKIR2 Schnorr. The latter source-pinned verifiers reject identity internally and are quiet. ZKIR3 is currently qualified only for 0.34.0; this rule supplies no guessed 0.35 ECDSA model. Unsupported profiles, relevant opaque predicates, lost provenance, unknown collection or struct projections, transformed verification operands, checkpoints, external composition, unfinished histories and exhausted allowances produce incomplete diagnostics. Known point constants are outside this unknown-key review. The default `identity-signature-key`, Jubjub enrollment and signed-input rules keep their existing contracts and observation cost. Preparation, observation, retained metadata, immutable keys, typed predicate closure and finding emission share the unchanged **40000 steps per entry, 256 paths per entry, 50000 cumulative abstract values per rule**. There is no separate proof allowance or retry. Experimental Counter-query mode lacks this exact observation contract and reports unavailable evidence when selected. From a built source checkout, select this rule with `node dist/src/cli.js scan examples/review/contract.compact --detectors signature-key-identity-exclusion-review --zkir-version 3`. Inspect its CLI metadata with `node dist/src/cli.js detector show signature-key-identity-exclusion-review --json`. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line signature-key-identity-exclusion-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/signature-key-identity-exclusion-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # split-witness-identity > Ledger-bound witness digest and mutation operand use independently supplied witness snapshots without mandatory equality binding. Canonical: https://nightshade.dicksonwu.xyz/rules/split-witness-identity.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `split-witness-identity` | | Severity | low | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | all-predicates, digest-inputs, collection-operations, original-write-history | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors split-witness-identity ./.nightshade/node_modules/.bin/nightshade detector show split-witness-identity ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/split-witness-identity.md at v0.1.1. Availability: opt-in. Severity: low. Confidence: high. Opt-in low severity, high confidence review of a precise static relationship. A successful history enforces a canonical native digest of exact witness input snapshots equal to definite preexisting ledger data. A Map/Set mutation key (or same-typed scalar Kernel mutation operand) uses entirely independent supplied witness snapshots. No mandatory scalar equality connects the observed guard digest or represented input leaves to the effect operand or its represented input leaves. Output digest equality and transitive scalar equality can bind the identities. Checks after the mutation count because they constrain the same successful transaction. The first implementation observes exact native digest inputs and resolved collection operation keys, not arbitrary arithmetic dependencies, stored value taint, wildcard write paths, or unrelated mutations. Aggregate Kernel operands, shielded-native recipient structures, collection lookups/member guards, and other protocol-specific authentication remain outside this contract. It does not interpret equal hash outputs as equal preimages. Fresh invocations of the same witness declaration remain independent; unchanged aliases retain identity. Ledger snapshots and revisions are not converted to live storage identities. Rule-isolated source observation uses all predicates and original histories. Missing predicate/digest/collection evidence, optional predicate alternatives that cannot be decoded, and exhausted allowances produce rule-scoped incomplete coverage and withhold findings. Baseline completion is independent. Experimental Counter mode has an absence certificate because the closed terminal Counter grammar excludes witnesses; other entries route to exact source observations. Both instruction/reference engines and cached/uncached transfers are covered by focused compiler-backed tests. Independent witness values can be intentional when the protocol treats the guard identity and mutation key as separate roles. The rule reports their unlinked source relationship; it does not infer caller intent or establish an authorization bypass. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line split-witness-identity -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/split-witness-identity.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # stored-schnorr-key-enrollment-review > Review stored supplied Schnorr keys with enrollment and enforced canonical use lacking modeled identity rejection. Canonical: https://nightshade.dicksonwu.xyz/rules/stored-schnorr-key-enrollment-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `stored-schnorr-key-enrollment-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | complete-cell-writers, surviving-point-write, exact-enforced-signature-outcome, original-all-predicate-histories | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors stored-schnorr-key-enrollment-review ./.nightshade/node_modules/.bin/nightshade detector show stored-schnorr-key-enrollment-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/stored-schnorr-key-enrollment-review.md at v0.1.1. Availability: **opt-in**, informational severity, high confidence in the represented source relationship. No policy required. Select with `--detectors stored-schnorr-key-enrollment-review`. Report a surviving raw entry-parameter Jubjub point write to a whole persistent Cell without modeled identity exclusion, paired with an enforced canonical `jubjubSchnorrVerify` use of an unknown entry-storage snapshot from the same declared Cell without modeled caller or internal identity exclusion. These are separate complete original histories. Common declaration identity does not prove equal values across transactions, a transaction sequence, identity feasibility, unsafe enrollment, sole authorization or application impact. The exact canonical verifier outcome must be asserted true. Discarded outcomes, constant-returning wrappers, negated-result assertions, another verifier's outcome and a namesake application circuit do not satisfy that condition. Aliases and helpers preserve exact outcome occurrences. Boolean constants, negation and asserted conjunctions are represented; dynamic Boolean equality/inequality relays containing that occurrence produce scoped incomplete diagnostics, including relays inside conjunctions or represented vector/struct comparisons. False or negated whole conjunctions containing that occurrence remain conservatively incomplete. The pinned 0.35.0 and 0.35.0-rc.1 successful canonical verifier calls reject identity internally and are quiet for this conjunction. All public writers, replacements, reachable helpers/imported instances and constructors are inventoried. The observer examines each successful history's final whole-Cell write; an unchecked temporary overwritten by a checked final point does not qualify. A later exact point check can reject the whole atomic invocation. Committed checkpoint histories are unsupported and produce scoped incomplete diagnostics. Complete writer inventory is not a claim that every stored point is valid. Implicit native defaults and construction are inventoried separately; a constructor's name or deployment use cannot establish trust. Checks must apply to the exact surviving operand or verifier snapshot. Guards on message data, another parameter, a prior key or a later storage revision do not validate it. Mandatory identity comparisons and qualified native identity-to-identity transfers stay within each original history. An asserted nonidentity `ecMul`/`ecNeg` result excludes identity of that exact recorded input, without establishing curve or subgroup membership. Guarded enrollment with an unchecked verifier use is quiet for this conjunction; the existing `enrolled-signature-key-review` remains independent, including default-state or initialization concerns. Relevant opaque predicates, lost identity/provenance, missing writer/use histories, malformed observations and exhausted shared allowances make the conjunction unavailable. Unrelated scalar/message checks do not donate validation. Identity compatibility with every constraint and a concrete successful identity input are not proved by missing represented identity exclusion. Preparation, all exact dependent histories, retained evidence, immutable keys, native/predicate closure and emitted proof rows share the unchanged observation limits (40000 steps, 256 retained paths, 50000 abstract values by default). Point/key traversals also have bounded depth and work limits. Baseline analysis and unrelated detector findings remain independent. The experimental Counter-query mode does not carry this compilation-unit enrollment proof and reports unavailable evidence when selected. A key enrollment can be intentionally managed by trusted setup or external governance that is not represented in the analyzed source. Such a design can match; the finding does not establish unsafe enrollment or a valid identity-key attack. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line stored-schnorr-key-enrollment-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/stored-schnorr-key-enrollment-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-default-getter-membership-review > Review explicit absent-to-zero getter evidence alongside an all-zero-success initial-membership Map decrement. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-default-getter-membership-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-default-getter-membership-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Authorization, identity and membership | | Engine facts used | exact-cross-entry-getter, source-key-pattern-binding, all-full-zero-successes, ordered-initial-membership, numeric-map-decrement | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-default-getter-membership-review ./.nightshade/node_modules/.bin/nightshade detector show zero-default-getter-membership-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 7/7 | 4/4 | 2/2 | 14/14 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-default-getter-membership-review.md at v0.1.1. Availability: **opt-in**, no policy required. Severity: **info**. Confidence: **high** for the supported static source relationship. Select with `--detectors zero-default-getter-membership-review`. `zero-default-getter-membership-review` is an opt-in informational source review. It infers neither token-standard semantics nor application policy. The existing `zero-amount-initial-membership` rule continues to require an explicit policy and retains its independent evidence. Admission requires a completed exported numeric getter whose exact histories return the immutable numeric Map lookup when present and explicit numeric zero for absence at every prefix of that lookup chain. Getter histories may not write storage or require unrelated gates. Within the getter, every membership query uses the actual raw parameter or constant operands of the returned lookup; matching types and parameter names do not supply equality. The corresponding spender's ordinary decrement operands select a directly bound exported numeric amount. With only that amount fixed to zero, every full successful history must decrement the same immutable lookup into its exact Map cell and require that cell initially. Ordered mutation/revision proof excludes supplied membership and uncertain origins. A successful zero bypass withholds the finding; a qualified explicit rejection is a quiet control, with no claim of successful zero execution. Cross-entry correspondence uses canonical ledger declaration identity plus ordered literal/raw-parameter key patterns. Parameter roles are alpha-renamed only for this cross-entry comparison, retaining types and repeated-use roles. The finding exposes the original parameter correspondence and does not claim that values from separate transactions are equal. Derived/aggregate operands and wildcard selectors do not qualify. Analysis is isolated from baseline facts, uses exact all-predicate histories, and keeps the existing 40,000-step / 256-path / 50,000-value defaults. This cross-entry pass shares its work/value allowance across relevant entries and admits at most 64 exported entries. An incomplete relevant entry withholds the whole relation and produces rule diagnostics. Ordinary baseline diagnostics and unrelated rules remain independent. Preparation, key roles/selectors, paths, prefixes, absence maps, certificates, helper snapshots and orchestration references consume the shared work/value allowance. Values count cumulative allocations; serialized text uses bounded 64-code-unit chunks and a conservative JSON-escaping reserve. Tight preparation or proof retention budgets produce incomplete coverage before unqualified evidence can be returned. Missing resolved callable/source closure also blocks structural absence. Reporting diagnostics remain available on exhaustion. Finding `initialRequirements` contains only exact raw cell keys along the selected lookup's prefix chain. Additional same-root requirements remain invocation gates and do not appear as supporting selected-chain evidence. Incomplete and rejected inputs provide no absence guarantee. The observer's raw scalar/constant key scope remains explicit above. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-default-getter-membership-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-default-getter-membership-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#authorization-identity-and-membership) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # checked-digest-narrowing > A full canonical hash is range-checked by a Uint cast on its source route to a ledger write or exported return. Canonical: https://nightshade.dicksonwu.xyz/rules/checked-digest-narrowing.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `checked-digest-narrowing` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | resolved-source, canonical-stdlib-calls, resolved-types, local-result-uses | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors checked-digest-narrowing ./.nightshade/node_modules/.bin/nightshade detector show checked-digest-narrowing ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/checked-digest-narrowing.md at v0.1.1. Availability: **opt-in**. Severity **informational**, confidence **high** for the resolved source relationship. Select with `--detectors checked-digest-narrowing`. Compact converts `Bytes` to `Uint` by decoding the entire byte vector as a little-endian integer and checking the target range. It does not truncate the value to the target width. A cast of a full hash to `Uint<64>` therefore checks all 32 bytes against `2^64 - 1`. ### Example, scenario and recommendation ```compact const digest = persistentHash>(value); const narrowed = digest as Uint<64>; recordedDigest = disclose(narrowed as Bytes<32>); ``` If the application meant to store a full digest identifier, retain `digest`. If a numeric projection is intended, define the exact byte selection or other protocol-approved projection before converting it. Preserve deliberate checked conversions. Altering an existing stored representation requires protocol and migration review. ### Matching and known intentional cases The rule follows a canonical `persistentHash` or `keccak256` `Bytes<32>` result through immutable local identity aliases, disclosure and identity casts. It reports a cast to a supported `Uint` type when the result, optionally re-encoded as Bytes, has a direct ordinary Cell assignment or scalar exported return in that resolved function. Custom exclusive Uint bounds retain their actual maximum. Findings group source uses per cast and canonical function instance. This is an entry-referenced source relationship, including syntactic dead branches and zero-iteration bodies. It does not prove successful execution, a failing input, every-path rejection, hash-output distribution, funds loss or deployed impact. Proof-of-work targets and intentional partial checked conversions can match; these intent-dependent shapes keep the rule opt-in. An explicit equality/bound elsewhere does not change the reported conversion semantics. Already bounded numeric encodings, selected/reconstructed/transformed digests, Field casts, arithmetic uses, aggregate returns, ADT/projected writes, outer captures and arbitrary helper-result forwarding are outside the matching scope. Canonical imported aliases and instantiated source modules are distinguished from application namesakes. A shared private/hash provenance is insufficient to establish an unchanged digest. ### Evidence and incomplete results Reference: Compact 0.34.0 source `1f671fc27818df2b2676b3a97f85b2b821756243`, `doc/compact-reference.mdx:3296-3304` and canonical hash API definitions. The owned Counter positive emits `convertBytesToUint(18446744073709551615n, 32, digest, …)` and preserves the original Counter increment. Corrected/full-digest and lookalike/bounded-encoding controls remain quiet. Compiler-only output inspection does not execute a runtime or proof and is not an independent bug label. The owned triplet compiles and retains the expected conversion shape on pinned 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0 and 0.35.0. The reported maximum is the declared source-type maximum. Compiler 0.30.0 emits a Number maximum literal and an older byte-encoding helper; later profiles emit BigInt. These compile-only checks do not qualify runtime cutoff equivalence across compiler/runtime versions. The source query charges traversal, depth, alias copies and entry copies. On exhaustion it discards partial observations and emits a rule-scoped incomplete diagnostic. Baseline analysis coverage remains separate; incomplete results are never clean. No scan budgets or engine transfers are changed by this rule. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line checked-digest-narrowing -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/checked-digest-narrowing.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # conditional-hash-range > Conditional unsigned subtraction reaches a fixed-width native persistent-hash input without a qualified inactive-case range invariant. Canonical: https://nightshade.dicksonwu.xyz/rules/conditional-hash-range.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `conditional-hash-range` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | resolved-source-references, resolved-types, canonical-native-calls | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors conditional-hash-range ./.nightshade/node_modules/.bin/nightshade detector show conditional-hash-range ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/conditional-hash-range.md at v0.1.1. Availability: **opt-in compiler compatibility review**, no policy required. Severity/confidence: **low/high**. Select with `--detectors conditional-hash-range`. A conditional unsigned subtraction can feed a fixed-width native hash input while its underflow assertion is guarded. In the qualified **Compact0.34.0/ZKIR2** output, a direct `Uint<128>` subtraction feeds `persistentHash>`'s 16-byte input without selecting safe operands when the source branch is inactive. The generated JavaScript keeps the computation inside the source branch; this rule does not describe that JavaScript as executing the inactive hash. ```compact import CompactStandardLibrary; export ledger digest: Bytes<32>; export circuit update(enabled: Boolean, a: Uint<128>, b: Uint<128>): [] { if (disclose(enabled)) { const difference = (a - b) as Uint<128>; digest = disclose(persistentHash>(difference)); } } ``` The finding identifies the subtraction, native hash input and controlling source branch. It is a static review relationship, **not proof of an invalid input, proof failure, runtime rejection or deployed vulnerability**. Earlier surviving unconditional ordering evidence and qualified safe inactive operand selections are quiet controls. A check inside the same conditional establishes only its active-case constraint. Select safe operands using the actual controlling condition before computing the hash preimage, and preserve intended active validation. Merely guarding the ledger assignment does not supply an inactive-case hash range invariant. Inspect the project's generated compiler output before relying on version-specific behavior. A direct hash of an already constrained `Uint<128>` input is a quiet lookalike. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line conditional-hash-range -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/conditional-hash-range.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # generic-witness-maybe-abi > Shared generic optional witness dispatch has incompatible mandatory bigint/byte-array payload guards; profile-specific compatibility review. Canonical: https://nightshade.dicksonwu.xyz/rules/generic-witness-maybe-abi.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `generic-witness-maybe-abi` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | resolved-source-references, canonical-generic-specializations, resolved-types | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors generic-witness-maybe-abi ./.nightshade/node_modules/.bin/nightshade detector show generic-witness-maybe-abi ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/generic-witness-maybe-abi.md at v0.1.1. Availability: **opt-in ABI compatibility review**, no policy required. Severity/confidence: **low/high**. Select with `--detectors generic-witness-maybe-abi`. Under Compact **0.34.0/ZKIR2**, concrete specializations of one generic witness dispatch to the same host method without a generic type argument. When its result is the canonical standard-library `Maybe`, the generated wrapper checks `value` even when `is_some` is false. A bigint payload and a byte-array payload cannot use one fixed absent-result placeholder. This rule reports the static signature relationship, with the declaration, conflicting return types and source reference sites grouped into one finding per canonical witness template. ```compact import CompactStandardLibrary; witness lookup(key: Bytes<4>): Maybe; export circuit getNumber(key: Bytes<4>): Maybe> { return disclose(lookup>(key)); } export circuit getBytes(key: Bytes<4>): Maybe> { return disclose(lookup>(key)); } ``` A shared host handler may distinguish keys, private state, call order or other context and return the correct typed payload. **This is not evidence that the handler fails.** Review absent-result handling and the generated witness signatures. Use distinct host witness names when incompatible result representations should have independent handlers. `Uint<64>` and `Field` are a quiet lookalike because their ordinary payload guards both accept `0n`. The rule requires identical concrete parameter types and known disjoint bigint/byte-array result representations. Resolved import/type aliases retain identity; separate concrete module instances and different witness declarations are kept separate. It describes the entry-reachable source/schema graph, including constant-dead references and zero-iteration callbacks whose wrappers the qualified compiler retains. It does not assert a successful invocation or proof feasibility. The compiler-only distinct-module probe also emits one shared host method spelling. This initial rule groups only one canonical template: a quiet distinct-instance control is a scope negative, not evidence of separate dispatch or ABI safety. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line generic-witness-maybe-abi -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/generic-witness-maybe-abi.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # public-two-component-domain-review > Review a public two-input native digest lacking represented self binding and component default exclusion. Canonical: https://nightshade.dicksonwu.xyz/rules/public-two-component-domain-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `public-two-component-domain-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | exact-native-preimage, canonical-self-provenance, all-successful-predicates, scalar-entry-input-identity | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors public-two-component-domain-review ./.nightshade/node_modules/.bin/nightshade detector show public-two-component-domain-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 6/6 | 5/5 | 3/4 | 4/5 | 1 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / publicTwoComponentDomainReview43/drafts/owner-domain43/lookalike.compact | lookalike | [15] to [15] | control hit | | manifest.json / publicTwoComponentDomainReview43/drafts/owner-domain43/opaque-salt-guard.compact | negative | [] to [] | incomplete or unvalidated | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/public-two-component-domain-review.md at v0.1.1. Availability: **opt-in**, no policy required. Severity: **info**. Confidence: **high** for the stated source relationship. Select with `--detectors public-two-component-domain-review`. This review observes a public ledger write containing a canonical native `persistentHash` of exactly two distinct scalar entry parameters of type `Bytes<32>`. The represented preimage lacks a canonical `kernel.self()` value, and assigning both components their default bytes is compatible with supported component-only scalar equality guards on a modeled successful history. Findings identify the actual native hash span, the two parameter declarations and the public write. An authorization consumer is unnecessary. The scope deliberately excludes a history when either component's default is excluded by a required supported equality guard. Thus both `salt != default` and `owner != default` can be quiet, independently of self binding. This is a narrower source surface, not a general repair of an owner/salt domain obligation: an owner restriction may still admit default salt, and nonzero salt alone does not establish uniqueness or instance separation. Late checks constrain complete successful histories. Exclusive branches retain separate guards. Canonical self must reach the actual preimage. A helper-returned self value or its exact bytes projection qualifies; storing self separately does not. A known single-component identifier, a single aggregate parameter, constant component, repeated parameter or other fully represented shape is outside the two-scalar scope. Other native hash/commitment primitives are outside this initial rule. Opaque or transformed preimages, opaque component guard operands, missing exact history evidence and exhausted preparation/proof budgets yield rule-scoped incomplete diagnostics. Absence of a rejection check alone never supplies a feasible-default claim. Baseline-incomplete entries withhold structural absence; standalone preparation also requires a complete resolved callable closure. Preparation, exact interpretation, traversal and retained certificates share the existing limits: 40,000 steps per entry, 256 paths and 50,000 cumulative abstract values. Instruction/reference and cached/uncached execution preserve the same findings. Values measure cumulative abstract allocation units, not physical memory. The ordinary scan remains independent of this opt-in observation pass. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line public-two-component-domain-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/public-two-component-domain-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # published-digest-generator-scalar-review > Published exact digest determines a scalar used in native generator multiplication whose result survives in a ledger Cell. Canonical: https://nightshade.dicksonwu.xyz/rules/published-digest-generator-scalar-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `published-digest-generator-scalar-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | resolved-calls, private-provenance, public-sinks, direct-hash-inputs, exact-invocation-operands | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors published-digest-generator-scalar-review ./.nightshade/node_modules/.bin/nightshade detector show published-digest-generator-scalar-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 4/4 | 4/4 | 4/4 | 6/6 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/published-digest-generator-scalar-review.md at v0.1.1. Availability: opt-in. Severity: info. Confidence: high. The rule observes selected native and cast operand/result snapshots in ordinary data flow. Selection enables the observer token; default scans retain their prior transfer paths. Legacy admission checks the resolved canonical native overload consumes `Field`; modern admission checks the canonical `JubjubScalar` overload. The legacy trace contains no invented cast. ZKIR 3 captures the ordinary scalar-cast result after its existing transfer; native interpretation and cast semantics are unchanged. Other compiler profiles remain explicitly unsupported when applicable. Matching uses owned semantic identities and immutable value keys, not function names, witness dependence alone, or wildcard storage paths. Later writes invalidate point survival. Both instruction/reference engines and cached/uncached execution use the shared transfer machinery. Exhausted observation or matching budgets produce incomplete diagnostics. Unsupported profiles produce a selected-rule diagnostic. A bounded resolved-call walk first checks whether an entry can reach canonical native generator multiplication. Unrelated entries need no scalar observations and are recorded as structurally absent. Renamed native imports and ordinary helpers retain their canonical targets; represented callbacks remain relevant even at zero iterations. Unresolved callable models and exhausted applicability budgets remain incomplete. Relevant entries still require the exact observations and qualified profile. The candidate is appended to the registry, preserving prior rule order. The finding establishes that the published digest determines the scalar in this exact source recipe. It does not establish encryption use, unsafe enrollment, ciphertext compromise, deployed impact or path feasibility. Root point Cells only; aggregate, collection and exported-return publication/registration patterns are outside the candidate's bounded support. Domain-tagged hashes and independent witness invocations do not match. Other deterministic scalar recipes are outside support. Preparation, source observation, exact matching, immutable-key work and retained allocations share unchanged 40k entry steps, 256 entry paths and 50k cumulative rule values. Selected facts carry their original limits and spent entry work; matching is aggregated after completion or refusal. Exhausted facts are not retried. No-entrypoint sources skip nonexistent entry preparation and keep their explicit complete label. Publishing a digest that determines a scalar can be an intentional protocol choice. Review how that scalar is used before treating the source relationship as a privacy or enrollment defect; this rule does not infer encryption or key management intent. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line published-digest-generator-scalar-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/published-digest-generator-scalar-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # secret-binding-divergence-review > Same-key ledger writers enforce different domain-qualified secret-binding declaration families. Canonical: https://nightshade.dicksonwu.xyz/rules/secret-binding-divergence-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `secret-binding-divergence-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | secret-binding-histories, successful-predicates, digest-inputs, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors secret-binding-divergence-review ./.nightshade/node_modules/.bin/nightshade detector show secret-binding-divergence-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 7/7 | 2/2 | 2/3 | 9/9 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / secretBindingDivergence49/drafts/secret-binding49/controls/intentional-weaker-same-key.compact | lookalike | [18] to [18] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/secret-binding-divergence-review.md at v0.1.1. Availability: **opt-in** with `--detectors secret-binding-divergence-review`. Findings are informational source comparisons requiring intent review. The rule compares exported numeric Map mutation occurrences on the same canonical ledger declaration. One writer already binds its affected exact key to an unchanged pre-existing record through a private, constant-domain-qualified native hash preimage. A completed sibling writer binds its own affected key to that binding family and an additional family with a different canonical witness declaration, constant domain recipe and trusted ledger declaration. Every successful sibling history must contain an occurrence enforcing both families at its own exact key. One sibling is enough for a comparison; no majority premise applies. These are declaration-family descriptors, not equality of private inputs, witness results or account values across entries. Each key equality is established only inside its original history: ordinary Map transfer derives the recorded storage path from the exact immutable lookup/insertion operand. The selected transfer meters that derivation and its retained encodings. Wildcard paths never establish equality. The matcher compares these exact operand encodings within the history, admitting direct, transitive and late atomic key equality only through required successful predicates. Optional and unequal-key predicates do not supply that equality. It compares only declaration-family descriptors between writers. The required equality graph does not rebuild different compound key encodings or derive function congruence from equal arithmetic/native inputs. Different derived or compound operand encodings without a graph-proved whole-operand equality produce explicit incomplete coverage. Identical exact encodings remain admissible; a shared wildcard path never does. This conservative boundary prevents a discarded additional binding from becoming a false missing-binding review. Scalar-source classification uses the canonical represented declaration type, including when the interpreter leaves a large aggregate unexpanded. Missing runtime `items`/`fields` metadata cannot turn an opaque compound key into a scalar key. The admitted hash recipe contains one raw scalar `Bytes<32>` witness input and fully represented constant components, using canonical `persistentHash`. The descriptor retains its primitive, input type and constant recipe. Published or publicly fixed preimages, transformed inputs, incomplete recipes, changed trusted record revisions and different effect keys cannot supply this relation. Boolean alternatives contribute only their required intersections. A late binding against an unchanged exact pre-existing record remains a constraint on atomic successful completion; its position does not manufacture a missing binding. The comparison concerns a mutation occurrence. Subsequent writes to another balance key do not erase an earlier occurrence. Trusted authentication-record revisions must remain unchanged at the compared effect and assertion. Enrollment without a base authentication binding is outside this review, as are List effects and inferred account groupings across different ledger declarations. Reachable canonical kernel checkpoints, including those in helpers or callbacks, produce explicit incomplete coverage during the selected metered callable walk. Committed-prefix semantics are outside this initial atomic-history review; an application circuit merely named `checkpoint` does not trigger that refusal. Selected preparation, ordinary execution, retained capture, identity traversal, matching and finding construction share the production limits: 40,000 steps per entry, 256 paths per entry and 50,000 cumulative abstract values per rule. Missing, unfinished or refused evidence produces diagnostics and incomplete rule coverage; there is no retry or quiet result from a truncated sibling inventory. The rule does not compare authentication strength or infer required policy, feasibility, exploitability, cryptographic independence or application impact. An intentionally different writer with this executable relationship still matches. This rule remains opt-in because its intent-dependent matches require independent review. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line secret-binding-divergence-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/secret-binding-divergence-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # transient-digest-to-ledger > Terminal ledger data is constructed using an upgrade-unstable transient hash or commitment. Canonical: https://nightshade.dicksonwu.xyz/rules/transient-digest-to-ledger.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `transient-digest-to-ledger` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | transient-data-origins, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors transient-digest-to-ledger ./.nightshade/node_modules/.bin/nightshade detector show transient-digest-to-ledger ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/transient-digest-to-ledger.md at v0.1.1. Availability: **opt-in**, no policy required. Severity/confidence: **low/high**. Select with `--detectors transient-digest-to-ledger`. The standard library documents that `transientHash` and `transientCommit` lack upgrade stability and should not derive state data. This rule reports a terminal modeled ledger operand constructed using either authenticated native primitive. It groups each primitive source site and entry, listing affected writes and invocations. It does not establish an actual upgrade failure, secrecy requirement, concrete feasibility or vulnerability. ```compact export ledger fingerprint: Field; export circuit register(value: Field): [] { fingerprint = disclose(transientHash(value)); } ``` A fingerprint that must be recomputed after a compiler/protocol upgrade needs a stable derivation. Use `persistentHash` or `persistentCommit` over stable inputs when that is the required lifecycle. Changing an existing representation requires an explicit migration. A persistent hash around a transient result still depends on the transient algorithm. Intentional version-bound state, ephemeral caches and compiler disclosure tests can match, so this compatibility review remains opt-in. The origin annotation describes syntactic data derivation, independently of private inputs. It survives modeled arithmetic, casts, helpers, snapshots and aggregate construction; projecting another aggregate member does not inherit an unrelated origin. Ambient control guards and arbitrary witness callback arguments do not establish data derivation. Consistency-only assertions, return/event-only outputs, namesake user functions, persistent-only derivations and definite final overwrites stay quiet. Origins do not establish value equality or live storage. Exact bounded observations are isolated from baseline analysis. Native hashes and commitments, ordinary storage operands and Map keys/values are supported. The observer disables compressed folds/hash choices and retains the original 40,000-step/256-path/50,000-value limits. Origins are limited to128 source sites; the consumer shares200,000 applicability/lifetime/grouping checks. May-value origins, wildcard/may-alias or partial overwrites, unsupported List/Merkle payload lifetimes and exhaustion produce explicit rule/entry-scoped incomplete diagnostics. Set removal after a transient-derived insertion is unavailable: whole-Set writes do not expose enough element lifetime evidence. A final exact reset can discharge an earlier uncertain operand. Other rules and baseline completion remain separate. This does not track arbitrary TypeScript witness code or cross-entry upgrades. Compiler acceptance and analyzer behavior are validated separately. The rule does not establish application recall or an upstream defect. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line transient-digest-to-ledger -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/transient-digest-to-ledger.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unconstrained-witness-to-state > A raw witness leaf reaches surviving ledger state without a modeled assertion using that leaf. Canonical: https://nightshade.dicksonwu.xyz/rules/unconstrained-witness-to-state.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unconstrained-witness-to-state` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | successful-predicates, private-provenance, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unconstrained-witness-to-state ./.nightshade/node_modules/.bin/nightshade detector show unconstrained-witness-to-state ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. A witness chooses the allocation written to the ledger without a preceding bound on that value. Full example: https://nightshade.dicksonwu.xyz/examples.md#unconstrained-witness-to-state ```compact // Owned synthetic witness-to-state regression. import CompactStandardLibrary; export ledger allocation: Uint<64>; witness rewardAmount(): Uint<64>; export circuit allocate(): [] { const value=rewardAmount(); allocation=disclose(value); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Raw witness value reaches ledger state without a value-specific assertion [unconstrained-witness-to-state] vulnerable.compact:7:15 7 | const value=rewardAmount(); | ^ allocate writes raw output of rewardAmount into allocation on a modeled successful history without an assertion depending on that witness leaf. Disclosure permits publication; it does not validate the value. An unrelated caller guard or a witness attestation about the value supplies no circuit validation. Public registration and prover-chosen metadata can be intentional; review the required application relation. Source: vulnerable.compact:7:15 Call path: allocate Remediation: If this field must represent an independently established fact, enforce the required relationship in the circuit using the exact supplied value. Document intentionally prover-chosen data. Review authorization and the adequacy of the check separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Assert a bound on the witness value before writing it. ```compact // Owned synthetic witness-to-state regression. import CompactStandardLibrary; export ledger allocation: Uint<64>; witness rewardAmount(): Uint<64>; export circuit allocate(): [] { const value=rewardAmount(); assert(value<=100,"reward allocation"); allocation=disclose(value); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unconstrained-witness-to-state.md at v0.1.1. Availability: **opt-in review**, medium severity, low confidence for application risk. ### Description, example and scenario ```compact const value = rewardAmount(); // witness allocation = disclose(value); ``` A raw witness leaf reaches surviving ledger state on a modeled successful history without a circuit assertion using that exact leaf. Disclosure permits publication, it does not validate the value. If a reward allocation must match an independently established fact, this is a useful review point. The SDK seed removes an owned required reward assertion; it is not an upstream vulnerability. ### Recommendation Assert the intended application relationship using the actual written witness value, and review the adequacy of that relationship independently. An unrelated caller guard, a check on another return leaf/call, and a witness Boolean attesting about the value do not validate that value in the circuit. Document deliberately prover-chosen metadata, registration and other public input policies. ### Evidence, limitations and known false positives Exact instruction/reference histories and cached/uncached transfers preserve witness invocation/leaf identity. Required assertion dependencies are projected through Boolean alternatives; a branch choice alone is not an assertion. Self-comparisons/private echoes supply no check. Later atomic assertions count; later definite overwrites, constructors, rejected histories, parameter-only data, transformed/hash values and explicit casts are outside this narrow review. Wildcards cannot establish definite overwrites. Findings group a witness site within an entry and list affected writes and invocations. An assertion dependency is not proof that a relation meaningfully restricts the value, that authentication is sound or that an invariant holds. Custom constraints, implicit conversions, control-only influence and transfer-only uses are outside scope. Public registration and prover-chosen application metadata are known intent-dependent shapes: the rule remains opt-in. Exhausted or missing exact observations/projections produce rule/entry-scoped incomplete diagnostics; baseline analysis and independent-entry findings remain available. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unconstrained-witness-to-state -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unconstrained-witness-to-state.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#unconstrained-witness-to-state) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # witness-derived-value-review > Review direct witness-derived canonical-send recipients without an exact prior ledger equality binding. Canonical: https://nightshade.dicksonwu.xyz/rules/witness-derived-value-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `witness-derived-value-review` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Privacy and cryptographic derivations | | Engine facts used | resolved-model | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors witness-derived-value-review ./.nightshade/node_modules/.bin/nightshade detector show witness-derived-value-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks The 0.1.1 proof run had no mapped synthetic corpus checks for this rule, so there are no measured results to show here. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/witness-derived-value-review.md at v0.1.1. Opt-in, low-confidence review. Flags a canonical send whose recipient comes directly from a witness result or its projection without an earlier exact equality assertion binding it to a ledger-derived value on the same branch. Prover-selected recipients can be intentional; the rule does not establish payment policy or review every amount source. Uses canonical send and witness identities, local aliases and separate branch states. Direct calls are supported; helper-mediated constraints are outside this review. Unsupported loops and exhausted traversal budgets produce diagnostics. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line witness-derived-value-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/witness-derived-value-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#privacy-and-cryptographic-derivations) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # exported-shielded-descriptor > Canonical shielded coin descriptor fields have an unchanged source route to an exported result. Canonical: https://nightshade.dicksonwu.xyz/rules/exported-shielded-descriptor.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `exported-shielded-descriptor` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | resolved-source, canonical-stdlib-calls, resolved-types | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors exported-shielded-descriptor ./.nightshade/node_modules/.bin/nightshade detector show exported-shielded-descriptor ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 3/3 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/exported-shielded-descriptor.md at v0.1.1. A finding means canonical shielded coin descriptor fields have an unchanged source route to an exported Compact result. Canonical `sendShielded`, `sendImmediateShielded`, and `mintShieldedToken` results retain their native identity. Canonical `ShieldedCoinInfo` and `QualifiedShieldedCoinInfo` inputs, resolved references, defaults and constructions retain represented descriptor fields. Import aliases retain canonical identity; user types and circuits with the same names do not establish this fact. The output boundary is the Compact/application result, not necessarily a public ledger. Wallet metadata APIs may deliberately return these values and still match. The finding establishes neither successful execution nor public ledger publication, secrecy-policy violation, exploitability or deployed impact. Existing explicit secrecy policies and native operation sink treatment remain independent. The source pass preserves immutable local aliases, disclosure, identity casts, represented structs and sequences, field selection, literal sequence indexing, helper arguments and helper result forwarding. It inspects syntactic branches and returns without claiming path feasibility. Aggregate projection selects the represented field; an unrelated field or helper argument does not inherit coin provenance. A `Maybe.is_some` flag alone does not expose a descriptor field. Known canonical hashes/commitments end the unchanged-field route. Arithmetic, comparisons and representation-changing casts are outside this contract. Relevant unresolved forwarding, opaque calls, callbacks, mutations, unsupported projections, loops in applicable source routes, recursive forwarding, and exhausted work/depth/layout allowances emit rule-scoped `shielded-descriptor-provenance-unavailable`. A missing provenance certificate never substitutes for a finding-free complete relevant route. The pass has one shared 20,000-work allowance across entries and helper expansion, depth 64, and represented sequence layouts up to 256 elements; its work is recorded in scan metrics. These source limits are separate from the ordinary path interpreter's analysis budgets. An intentional metadata return can match this rule. Review the recipient and disclosure policy before treating the result as a defect or suppressing it. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line exported-shielded-descriptor -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/exported-shielded-descriptor.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # permissionless-mint-egress > Permissionless mint and egress compose around a stored-value boundary without a modeled authorization predicate. Canonical: https://nightshade.dicksonwu.xyz/rules/permissionless-mint-egress.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `permissionless-mint-egress` | | Severity | high | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | runtime-operations, successful-predicates, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors permissionless-mint-egress ./.nightshade/node_modules/.bin/nightshade detector show permissionless-mint-egress ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/permissionless-mint-egress.md at v0.1.1. Availability: **opt-in effect review**, no policy required. Severity/confidence: **high/low**. The rule correlates a canonical mint effect with an unguarded token egress effect. It requires an unguarded mint authority and a completed successful history; beneficiary or buyer predicates may guard the egress. It recognizes named supply/treasury state, a shared token domain, or a same-root permissionless pair as the stored-value boundary. Standard-library mint/send wrappers are mapped back to their user call sites; internal mint claims and output-counter lowerings are not treated as separate withdrawals. Remediation: bind mint and egress to an authenticated role or protocol state, and enforce the supply/custody invariant across both circuits. An amount cap alone does not establish that invariant. Intentionally permissionless minting, treasury flows, or public claims can match when they meet the structural conditions. Review the intended supply and custody policy before treating the finding as a defect. The analysis does not establish runtime feasibility, asset loss, or deployed impact. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line permissionless-mint-egress -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/permissionless-mint-egress.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # received-coin-not-validated > Received shielded coin lacks a recorded application constraint on color or value. Canonical: https://nightshade.dicksonwu.xyz/rules/received-coin-not-validated.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `received-coin-not-validated` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | successful-predicates, all-predicates, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors received-coin-not-validated ./.nightshade/node_modules/.bin/nightshade detector show received-coin-not-validated ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/received-coin-not-validated.md at v0.1.1. Availability: **opt-in** with `--detectors received-coin-not-validated`; no policy required. Severity **low**, confidence **low**. Explicit selection replaces the default detector set. Owned example: the compiler-qualified [fixture](#example-1) adapts an SDK deposit with an owned fixed-payment requirement, then substitutes a tautological amount check. The [correction](#example-2) checks the expected color and value `10` before receipt. Review a fixed-price payment flow; recommendation: constrain the exact received coin to the intended trusted terms. The original unrestricted SDK deposit is not labeled vulnerable. For example, a payment circuit that calls `receiveShielded(disclose(coin))` without checking its price can accept a payment outside the intended terms. Check `coin.color == expectedColor` and `coin.value >= price` against trusted ledger terms or constants. The rule also recognizes exact value equality and positive constant lower bounds. It does not prove those terms implement the intended business policy. Evidence comes from completed entry histories, canonical standard-library call identity, exact received operands and enforced predicates. Equality aliases, helpers, negated comparisons, branch alternatives and checks after receipt are supported. Later checks constrain atomic success. Checks on another coin, ignored comparisons, self-equality, `Uint >= 0`, arbitrary caller-supplied terms and self-written ledger values do not establish validation. Exhausted query or analysis budgets remain incomplete. Known limits: custom receipt protocols, unshielded receipts, arithmetic-derived pricing and arbitrary policy inference are outside this rule. A generic wallet, forwarder, donation or deposit handler may intentionally accept any coin. Select explicitly with `--detectors received-coin-not-validated`. The compiler-valid positive/corrected/lookalike cases live in the existing corpus. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/received-coin-not-validated.compact`). ```compact // SDK shielded-map fixture with an owned fixed-payment policy; see known-bugs.json. import CompactStandardLibrary; export ledger counter: Counter; export ledger reward: QualifiedShieldedCoinInfo; witness dummy(): []; export circuit deposit(coin: ShieldedCoinInfo): [] { assert(coin.color == default>, "expected color"); assert(coin.value == coin.value, "expected amount"); receiveShielded(disclose(coin)); reward.writeCoin(disclose(coin), right(kernel.self())); counter.increment(1); dummy(); } ``` #### Example 2 Correction (source: `tests/corpus/safe/received-coin-not-validated.compact`). ```compact // SDK shielded-map fixture with an owned fixed-payment policy; see known-bugs.json. import CompactStandardLibrary; export ledger counter: Counter; export ledger reward: QualifiedShieldedCoinInfo; witness dummy(): []; export circuit deposit(coin: ShieldedCoinInfo): [] { assert(coin.color == default>, "expected color"); assert(coin.value == (10 as Uint<128>), "expected amount"); receiveShielded(disclose(coin)); reward.writeCoin(disclose(coin), right(kernel.self())); counter.increment(1); dummy(); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line received-coin-not-validated -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/received-coin-not-validated.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # shielded-burn-amount-width > An exported amount is forwarded unchanged to a canonical shielded burn whose coin and API amount types are wider. Canonical: https://nightshade.dicksonwu.xyz/rules/shielded-burn-amount-width.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `shielded-burn-amount-width` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | resolved-source, canonical-stdlib-calls, resolved-types | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors shielded-burn-amount-width ./.nightshade/node_modules/.bin/nightshade detector show shielded-burn-amount-width ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-burn-amount-width.md at v0.1.1. Availability: opt-in. Severity: info. Confidence: high. Resolved symbol identity excludes user-defined namesakes. Immutable local aliases, disclosure, identity/widening casts and linear pure helper return forwarding preserve the exact parameter/recipient identity. Arithmetic, mutable aliases, non-pure wrapper calls, complex helper control flow, callback bodies and captured parameters are outside this certificate. Ordinary recipient payments stay quiet. This is a syntactic type relationship, including source branches and loop bodies, not a successful-history claim. Intentional small burns can match. Available balances, feasible transactions, proof success, inability to split burns and deployed impact are not proved. Review the intended limit before widening an API. The bounded owned-model pass emits rule-scoped incompleteness on exhaustion. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line shielded-burn-amount-width -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-burn-amount-width.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # shielded-contract-recipient-review > Review canonical shielded sends with a modeled non-self ContractAddress recipient arm. Canonical: https://nightshade.dicksonwu.xyz/rules/shielded-contract-recipient-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `shielded-contract-recipient-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | exact-canonical-send-operand, complete-successful-histories, non-self-contract-arm | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors shielded-contract-recipient-review ./.nightshade/node_modules/.bin/nightshade detector show shielded-contract-recipient-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 1/1 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-contract-recipient-review.md at v0.1.1. Availability: **opt-in**, informational severity. No policy required. Select with `--detectors shielded-contract-recipient-review`. This rule reports an exact canonical `sendShielded` or `sendImmediateShielded` call on a complete modeled successful history whose recipient selects the `ContractAddress` arm of native `Either` and has an enforced exact non-self address relation. Its supported applicable scope is Compact 0.34.0 / ZKIR2. Canonical call and native type identity, exact recipient operands and immutable byte relations supply the evidence; application names and shared wildcard paths do not. Review how the transaction supplies the recipient contract's matching receive/claim composition. External same-transaction composition is unmodeled. The finding does not establish a missing claim, transaction rejection, concrete path feasibility or security impact. Intentional forwarding and testing helpers can match. Account-only and exact self-recipient controls remain quiet. The ordinary pass and admitted top-level native recipient-tag specializations share the unchanged allowances: 40,000 steps, 256 retained paths and 50,000 cumulative abstract values by default. All required passes must finish before findings are admitted. Unknown or opaque tags, unavailable exact histories, unsupported applicable profiles, checkpoints, external contract-call composition and exhausted allowances produce scoped incomplete diagnostics. Structural absence does not provide an absence guarantee for incomplete baseline semantics. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line shielded-contract-recipient-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shielded-contract-recipient-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # signed-effect-input > Review ordinary state or shielded input coin sources absent from enforced signature message dependencies. Canonical: https://nightshade.dicksonwu.xyz/rules/signed-effect-input.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `signed-effect-input` | | Severity | low | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | successful-signature-calls, all-predicates, original-write-history | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors signed-effect-input ./.nightshade/node_modules/.bin/nightshade detector show signed-effect-input ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 3/3 | 3/3 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/signed-effect-input.md at v0.1.1. Availability: **opt-in**; low severity, medium confidence. No policy required. Opt-in, low severity intent review. On an original modeled successful exported circuit history, a canonical `jubjubSchnorrVerify` Boolean result is explicitly enforced before an ordinary scalar ledger assignment. The assigned value has a caller parameter or witness source absent from the signed message's represented dependencies. The exact finding is **effect input not among signed message dependencies**. A known benign pattern is an unsigned effect input constrained by a separate trusted guard or intentionally left outside the signed statement. This is neither a sole authorization claim nor an exploitability claim. The owned rule uses exact canonical signature observations, all successful predicates, immutable write snapshots, and mandatory Boolean equality closure. Transparent aliases and transitive Boolean equalities are supported; common source provenance never establishes value equality. A returned `false` alone does not abort a history or enforce an unused signature. Later aborts remove the history. A namesake verifier and an unrelated repeated signature cannot supply enforcement for another observed result. Aggregate dependency leaves retain their individual source identities. Scalar-state scope excludes constructors, nested/aggregate storage, Counter and collection effects and network/fork/preimage binding claims. Signatures enforced only after a write are outside this conservative initial ordering scope. This does not require every effect input to be signed. No key trust or message protocol interpretation is inferred. A signed message containing the chosen effect input suppresses this source observation; a constant-only effect supplies no independent source to report. Integration: register `signedEffectInput` from `src/detectors/signed-effect-input.ts` with `defaultEnabled: false`. Select canonical signature observation (`signatureEvidence` / `observeSignatures`), retain `predicateScope: "all"`, and use `pathSemantics: "equivalent-states"`. Configure the ordinary interpreter with fold partitions and hash choices disabled to retain original histories. The rule has a one-million-unit allowance, and equality decoding has the shared bounded allowance/depth. Missing evidence or exhausted work produces rule-scoped incomplete diagnostics through the caller. Baseline transfer incompleteness prevents findings for the affected entry. Owned tests use harmless Field assignments and compiler `--skip-zk` acceptance; no contract execution or proof generation is needed. Tests compare instruction and expression engines with summaries enabled and disabled. The same opt-in rule also reviews the input nonce at canonical `sendShielded` (including the inner call of `sendImmediateShielded`). It retains the full input argument before the send body and uses only mandatory predicates preceding that operation boundary. A check after the send cannot donate authorization or operand binding. Canonical Schnorr and ZKIR3 ECDSA verifications are recognized separately; missing verifier/send observation markers or ordering boundaries remain incomplete. Sibling coin fields and repeated calls retain distinct leaf identities. Exact digest inputs and scalar equality closure allow a separately supplied input nonce constrained to signed data to stay quiet. The exact review is **input coin nonce absent from signed message dependencies**. Coin nonce is not claimed to be a complete coin identity. Dependence is not a proof of injective serialization, trusted key, signature quorum, sole authorization or replay resistance. The owned typed ECDSA approval seed covers operation, self address, approval nonce and amount, then demonstrates the independent input nonce omission as a static source pattern. Its correction includes the full coin in the digest. It is not an executable reproduction of the historical approval protocol. Network/fork, preimage-only and issuer-descriptor findings remain separate misses. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line signed-effect-input -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/signed-effect-input.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unbounded-mint > A variable mint amount has no modeled per-call cap below the native range or public ledger bound. Canonical: https://nightshade.dicksonwu.xyz/rules/unbounded-mint.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unbounded-mint` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | successful-predicates, canonical-mint-observations, numeric-bounds | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unbounded-mint ./.nightshade/node_modules/.bin/nightshade detector show unbounded-mint ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unbounded-mint.md at v0.1.1. Availability: **opt-in review**, medium severity, low confidence for monetary-policy risk. ### Description, example and scenario ```compact mintShieldedToken(domain, disclose(amount), nonce, recipient); ``` A variable native mint amount retains the full 64-bit upper limit on a modeled successful history, without a recognized public-ledger upper bound. A positive-only check and an unrelated authorization guard do not establish a per-call quantity cap. Review whether the application intended a tighter reward or issuance limit. This is a quantity review, not a claim that every public mint is a vulnerability. ### Recommendation Constrain the actual minted amount to the intended per-call limit if required by monetary policy. Protect supply, issuer authorization and public cap integrity separately. A local amount cap does not establish a cross-transaction supply invariant. ### Evidence and known false positives Exact shielded/unshielded kernel mint operands, immutable scalar snapshots, checked narrowing/type ranges and successful assertion constraints retain the actual amount. Later atomic assertions may constrain it. Constant amounts, narrower types, proved smaller upper envelopes and public-ledger upper/equality bounds (including transitive aliases, immutable Map snapshots and public numeric expressions) stay quiet. Numeric operand trees establish bound origins without claiming ledger digest/preimage provenance. A bound computed from the minted amount itself supplies no independent cap. Saved public bounds and pure later proof assertions also constrain checkpoint prefixes; later ledger-dependent checks only constrain the fallible segment. A value compared with itself supplies no extra upper bound. A guard on a different amount, private echo of the amount, new storage revision or sibling history supplies no cap for this value. Constructors and rejected histories are excluded. Observation/projection exhaustion is rule/entry-scoped incomplete and preserves baseline results. Trusted-issuer minting, intentionally public faucets and unrestricted issuance and public pending-balance withdrawals are known intent-dependent shapes; the rule remains opt-in. A recognized public bound is not proof that its storage is protected or its value reasonable. Only per-call limits are reviewed. Protocol pricing, custom mint effects, global supply invariants and arbitrary algebraic proofs remain outside scope. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unbounded-mint -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unbounded-mint.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unprotected-value-transfer > Successful token operations have no required application predicate constraining private caller inputs. Canonical: https://nightshade.dicksonwu.xyz/rules/unprotected-value-transfer.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unprotected-value-transfer` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | successful-predicates, all-predicates, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unprotected-value-transfer ./.nightshade/node_modules/.bin/nightshade detector show unprotected-value-transfer ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unprotected-value-transfer.md at v0.1.1. Availability: **opt-in** with `--detectors unprotected-value-transfer`; no policy required. Severity **low**, confidence **low**. Explicit selection replaces the default detector set. Owned example: the compiler-qualified [fixture](#example-1) exposes a canonical send without a required private caller predicate. Its [correction](#example-2) checks a private-key hash against stored owner data. Review whether the transfer is meant to be restricted; recommendation: enforce the intended caller/protocol check where required, and preserve documented public faucets or forwarding behavior. The requested rule reviews successful exported invocations of the canonical Compact standard-library `mintShieldedToken`, `mintUnshieldedToken`, `sendShielded`, `sendUnshielded` and `sendImmediateShielded` when no required caller-dependent check constrains the operation. It must identify actual operation reaches, including nested calls and replay; a user-defined helper with the same name is not a token operation. Constructors are outside the exported-operation claim. A condition merely mentioning a private value is insufficient. A branch with both arms reaching the same operation must not manufacture a required guard. Conversely, alternate real authentication in different arms and a late assertion constraining atomic success must remain valid. Successful predicates need full private-input scope; witness-only facts omit parameter checks. Effects and constraints must remain on the same history, and exhausted analysis must stay explicitly incomplete. An unguarded public faucet or mint can be intentional. This rule cannot infer that transfers should be private or privileged, or verify arbitrary cryptographic or protocol checks. ### Evidence query and limits Actual kernel/native histories identify canonical token helper invocations. An exported entry and operation form one group; nested invocation chains remain in the finding. Internal `sendShielded` calls inside `sendImmediateShielded` do not create a duplicate operation finding. Within each identical recorded public context, the bounded predicate-cover query checks whether the union of successful histories covers every Boolean valuation of their recorded private conditions. This cancels irrelevant reconverging branch choices while retaining an assertion, disjunction, branch-only transfer or alternative checks. Repeated witness invocations remain distinct atoms. The query reads completed histories; it does not execute new paths, solve numeric conditions or infer cryptographic validity. It excludes pinned stdlib recipient/change branches by canonical function identity, not source names. Application reuses of those conditions remain visible even when prior assumptions have refined them to constants. Literal truths and immutable self-equalities supply no constraint. Missing expression identity is opaque evidence, never an invented equality between unrelated values. The result means **no required predicate in this recorded application evidence**. Implicit overflow/cast/transaction checks still apply. The rule does not prove path feasibility or intended authorization. Arbitrary algebraic relationships between atoms, distinct but equivalent public contexts and opaque predicates can prevent a report. Private dependency does not certify a check's strength as authentication. The `spoofable-authorization` rule separately reviews raw witness equalities. Observation uses scope `all` and the existing engine value budget. Applicability is bounded to 20,000 graph operations; each cover query to 100,000 operations/depth 64 and condition keys to 65,536 characters before and after composition; total rule work to 1,000,000 operations. Missing invocation/predicate evidence, unsupported effects and exhaustion remain explicitly incomplete. A failed cover query returns no partial rule findings. Existing correlated/Counter domains do not execute these token operations and may certify their structural absence; their admission scope is unchanged. ### Usage, example and correction ```sh node dist/src/cli.js scan examples/review/contract.compact \ --detectors unprotected-value-transfer ``` Explicit `--detectors` selects that set rather than adding to defaults. Include other desired IDs in the comma-separated selection. The CLI marks this rule as `opt-in review`; JSON detector metadata has `defaultEnabled: false`. ```compact import CompactStandardLibrary; export circuit withdraw(recipient: Either): [] { sendUnshielded(default>, 1, disclose(recipient)); } ``` This is a review match when selected. If withdrawal should be restricted, enforce the intended caller or protocol check. The corrected corpus fixture asserts a private-key hash against stored owner data before sending. Public faucets and payment/forwarding flows should retain their intended policy; an opt-in match alone is not a reason to add an owner restriction. User-defined namesake helpers are quiet. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/unprotected-value-transfer.compact`). ```compact import CompactStandardLibrary; export circuit withdraw(recipient: Either): [] { sendUnshielded(default>, 1, disclose(recipient)); } ``` #### Example 2 Correction (source: `tests/corpus/safe/unprotected-value-transfer.compact`). ```compact import CompactStandardLibrary; export ledger owner: Bytes<32>; witness secret(): Bytes<32>; export circuit withdraw(recipient: Either): [] { assert(persistentHash>(secret()) == owner, "owner"); sendUnshielded(default>, 1, disclose(recipient)); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unprotected-value-transfer -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unprotected-value-transfer.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unshielded-refund-endpoint-review > Review a complete local refund-validator endpoint producing a zero remainder send expression. Canonical: https://nightshade.dicksonwu.xyz/rules/unshielded-refund-endpoint-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unshielded-refund-endpoint-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | source-local-formula-certificate | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unshielded-refund-endpoint-review ./.nightshade/node_modules/.bin/nightshade detector show unshielded-refund-endpoint-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 5/5 | 1/1 | 1/3 | 7/9 | 2 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/dynamic-map-snapshots.compact | negative | [] to [] | incomplete or unvalidated | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/intentional-endpoint.compact | lookalike | [58] to [58] | control hit | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/intentional.compact | lookalike | [58] to [58] | control hit | | manifest.json / refundEndpoint57/drafts/arithmetic-endpoint57/scalar-ledger-snapshots.compact | negative | [] to [] | incomplete or unvalidated | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unshielded-refund-endpoint-review.md at v0.1.1. Availability: **opt-in**; severity **info**. Qualified for compiler 0.34.0/ZKIR2 or ZKIR3; experimental Counter mode is unavailable. `unshielded-refund-endpoint-review` is opt-in and informational. It inspects a complete straight-line pure validator, matches its unsigned bounded floor relation, and evaluates the selected formal witness B=P=A=Q=1 through every statement, assertion, arithmetic intermediate and numeric cast. The validator assertion is tied by resolved lexical snapshot identities to a direct canonical send expression B-Q. Both Q*A+A and checked (Q+1)*A upper expressions are supported. The result is an independently complete source-local formula certificate. It proves that this selected formal witness satisfies the inspected formula and supported relevant local caller arithmetic checks, and yields zero in the tied remainder expression. It does not certify unrelated caller conditions, ledger reachability, successful histories, transaction or proof feasibility, send rejection or application impact. Intentional endpoints match. A quiet result after rejecting witness1 does not establish that another zero endpoint is impossible. Rule coverage uses `source-local-formula`. Baseline diagnostics and completion remain intact even when a local certificate completes. It never fills `completedEntries`, fabricates runtime paths or retries a failed ordinary analysis. Experimental Counter mode explicitly refuses the source certificate. The dedicated versioned evidence carrier and issued certificates are checked against the owning Program and compiler profile before emission. Discovery and evaluation share40k steps per entry,256 candidate mappings per entry and50k cumulative retained values per selected rule. Expression/CFG ownership, recursive operand discovery, formal evaluation, casts, assertions, key strings, source mappings and findings are metered. Failures retain scoped incomplete diagnostics without partial findings from the affected entry. Dynamic reads and raw ledger reads cannot be equated; a local initialized from storage is an opaque value snapshot. Exact tuple leaves and aliases preserve distinct lexical identity. The initial implementation supports compiler0.34.0/ZKIR2 or3. It refuses loop-contained sends, unsupported pure-body statements/calls, relevant opaque caller checks, mutable operand/guard snapshots, lost argument provenance, unsupported checked types and exhausted budgets. Unrelated caller conditions remain explicitly outside the formula theorem. Nested relevant conditional continuations are inspected as local implications; unresolved relevant conditions refuse rather than being assumed true. Discovery keeps a private immutable snapshot of caller expressions, source spans and resolved symbols. Public candidate maps cannot alter later certification; shared Program objects are not globally frozen. Finding preparation charges the actual emitted strings, imported source-file key lists and sorting, path normalization, discriminator replacements, fingerprint-key joining and UTF-8 hashing work before emission. These costs share the existing observation allowance. The initial checker inventory conservatively includes pure checkers from sibling branches. A relevant checker in an exclusive branch can therefore cause an incomplete result even when that branch would not run at the selected witness. This limitation is retained instead of claiming a complete path certificate or broadening branch analysis this checkpoint. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unshielded-refund-endpoint-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unshielded-refund-endpoint-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-amount-complementary-send-review > Review exact same-color complementary sends with two zero-inclusive amount envelopes. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-amount-complementary-send-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-amount-complementary-send-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | canonical-send-operands, complete-original-successful-histories, immutable-unsigned-subtraction | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-amount-complementary-send-review ./.nightshade/node_modules/.bin/nightshade detector show zero-amount-complementary-send-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 4/4 | 2/2 | 3/4 | 7/8 | 1 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / complementarySendReview47/drafts/complementary47/boundaries/intentional-same-executable-as-positive.compact | lookalike | [9] to [9] | control hit | | manifest.json / complementarySendReview47/drafts/complementary47/boundaries/persistent-map-lost-lineage-refusal.compact | negative | [] to [] | incomplete or unvalidated | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-complementary-send-review.md at v0.1.1. Availability: **opt-in**; severity **info**. Select it with `--detectors zero-amount-complementary-send-review`. The rule reports one complementary pair of canonical `CompactStandardLibrary.sendUnshielded` calls on a complete original successful invocation history. The calls use the same exact immutable token-color operand and send unsigned scalar snapshots `P` and `T-P`. Aliases and value-preserving casts retain the relationship. The exact total `T` must have a proven positive modeled lower bound, and **both actual sent amount envelopes must have lower bound zero** after all modeled mandatory checks, including late checks. ```compact assert(disclose(total) > 0 as Uint<128>, "positive total"); const remainder = total - part; sendUnshielded(disclose(color), disclose(part), disclose(recipient)); sendUnshielded(disclose(color), disclose(remainder), disclose(recipient)); ``` Review whether the application's allocation policy should conditionally skip exact zero endpoint sends. Intentional zero/full endpoint allocations may match. A guard that makes either sent amount positive quiets this rule. A literal-zero part with a positive total is quiet because its remainder is strictly positive. Independent fee amounts, different color snapshots, mutually exclusive calls, and Field subtraction do not establish the selected relationship. Supported profiles are Compact **0.31.1/ZKIR2** and **0.34.0/ZKIR2 or ZKIR3**. Admission counts possible canonical calls through helpers and callbacks, including zero-iteration callbacks. Closures without an unsigned subtraction or two possible canonical sends can establish structural absence without requesting a numeric profile. Original histories remain separate; cached and uncached transfers preserve the same operands and evaluation order. Exact read/storage summaries remain available; fresh computed scalar occurrences are interpreted rather than reused from cached results. Preparation, execution, immutable-key traversal, numeric bounds, pair matching, and emission share the existing **40,000 steps per entry, 256 paths per entry, and 50,000 cumulative values per rule**. Unsupported applicable profiles, checkpoints, lost arithmetic lineage, inconsistent or missing history carriers, unfinished baseline analysis, and exhausted allowances produce rule-scoped incomplete diagnostics. Experimental Counter-query histories do not supply this rule's exact observation evidence. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-amount-complementary-send-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-complementary-send-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-amount-unguarded-map-debit-review > Review an amount-zero successful numeric Map debit whose exact lookup has unknown prior membership. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-amount-unguarded-map-debit-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-amount-unguarded-map-debit-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | entry-zero-history, exact-map-lookup, numeric-subtraction, ordered-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-amount-unguarded-map-debit-review ./.nightshade/node_modules/.bin/nightshade detector show zero-amount-unguarded-map-debit-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-unguarded-map-debit-review.md at v0.1.1. Availability: **opt-in**, no policy required. Severity: **info**. Confidence: **high** for the supported static source relationship. Select with `--detectors zero-amount-unguarded-map-debit-review`. The observer selects actual debit operands from an ordinary successful invocation, then fixes an unchanged numeric entry parameter to zero. Literal-zero APIs use ordinary histories. It reports a numeric Map lookup whose exact immutable result is the minuend of that subtraction and is written to the same exact entry, without an intervening overlapping mutation, when membership was unknown before the lookup. Each lookup retains its own occurrence identity and helper arguments retain their actual values. One complete qualifying history suffices. Same-entry guards and exact prior insertions are quiet. Parent-only or different key membership does not establish the selected inner entry. A later guard does not establish membership before an earlier lookup. Positive-only APIs, addition, unrelated amounts, transformed debit parameters, different write keys and intervening may-alias writes do not qualify. An earlier successful same-entry lookup can establish membership, making a later debit read quiet. Unknown membership is not missing membership. The rule does not establish intended zero semantics, initial absence, runtime lookup failure, transaction feasibility or impact. Initial storage remains unknown; cross-invocation application invariants are not inferred. Intentional zero APIs can match. The dedicated observer retains explicit empty operation sequences. Missing lookup origins, operands, ordered writes or invocation evidence, reached checkpoints and exhausted budgets produce diagnostics. Ordinary analysis and the existing zero-membership policy remain unchanged. Incomplete and rejected inputs provide no absence guarantee. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-amount-unguarded-map-debit-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-unguarded-map-debit-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-amount-unshielded-send > Review canonical unshielded send amounts with a zero-inclusive successful-history range. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-amount-unshielded-send.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-amount-unshielded-send` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | canonical-invocation-snapshots, all-predicates, exact-numeric-operands, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-amount-unshielded-send ./.nightshade/node_modules/.bin/nightshade detector show zero-amount-unshielded-send ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-unshielded-send.md at v0.1.1. Availability: **opt-in**; severity **info**. This rule reviews canonical `CompactStandardLibrary.sendUnshielded` calls whose amount retains zero in its modeled successful-history range. The amount is the second argument (index 1). ```compact sendUnshielded(disclose(color), disclose(amount), disclose(recipient)); ``` An unsigned amount permits zero until an effective constraint excludes it. A literal zero is also a review candidate. Require `amount > 0` before sending when the intended operation requires a positive amount, or handle zero explicitly without invoking the send. A local circuit sharing the spelling is not the canonical operation. Zero-valued transfers can be intentional for protocol bookkeeping or a supported no-op. This informational rule reports only the modeled source amount; it does not infer application policy, prove a transaction can execute, or establish economic impact. Unsupported histories and exhausted budgets remain incomplete. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-amount-unshielded-send -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-amount-unshielded-send.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # zero-transfer-retained-list-review > Review zero-inclusive actual transfers paired with retained List append for the exact user recipient. Canonical: https://nightshade.dicksonwu.xyz/rules/zero-transfer-retained-list-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `zero-transfer-retained-list-review` | | Severity | info | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Token, coin and value transfers | | Engine facts used | canonical-invocation-snapshots, all-predicates, exact-collection-selectors, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors zero-transfer-retained-list-review ./.nightshade/node_modules/.bin/nightshade detector show zero-transfer-retained-list-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 3/3 | 2/2 | 3/4 | 3/5 | 2 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/intentional-zero-linked-growth.compact | lookalike | [12] to [12] | control hit | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/append-then-reset.compact | negative | [] to [] | incomplete or unvalidated | | manifest.json / zeroListGrowth50/drafts/zero-list50/controls/append-then-pop.compact | negative | [] to [] | incomplete or unvalidated | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-transfer-retained-list-review.md at v0.1.1. Availability: opt-in informational review. The rule flags a supported same-history pattern in which a zero-value transfer coexists with retained growth of a recipient List. It does not infer that the List is a reward, balance, or security-critical counter. A positive amount assertion on the actual sent value, including a later atomic assertion, excludes the observation. Independent amount parameters, matching names, shared dependencies and wildcard storage paths cannot establish the relation. Unknown recipient/key congruence, unsupported effects, exhausted budgets, checkpoint composition and later overlapping destructive writes produce incomplete diagnostics. Later List pushes preserve earlier appends. The observation shares the existing 40,000 entry steps, 256 histories and 50,000 cumulative abstract values across preparation, capture, matching and emission, without retries. An application may intentionally record zero-value events or retain a List entry for bookkeeping. Review the List's role before changing that behavior; the source relationship alone does not prove a free economic benefit or deployed impact. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line zero-transfer-retained-list-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/zero-transfer-retained-list-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#token-coin-and-value-transfers) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # caller-supplied-ledger-equality > An unchanged caller input must equal preexisting public ledger bytes before a state-changing effect. Canonical: https://nightshade.dicksonwu.xyz/rules/caller-supplied-ledger-equality.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `caller-supplied-ledger-equality` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | all-successful-predicates, private-provenance, exact-effect-histories | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors caller-supplied-ledger-equality ./.nightshade/node_modules/.bin/nightshade detector show caller-supplied-ledger-equality ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-ledger-equality.md at v0.1.1. Availability: **opt-in review**, no policy required. Severity/confidence: **medium/high**. Select with `--detectors caller-supplied-ledger-equality`. An unchanged caller-supplied `Bytes<32>` leaf must equal definite preexisting public ledger bytes before every modeled successful reach of an affected write or Kernel effect. The finding groups one guard site per entry and lists the actual effects, invocations and immutable ledger identities. Neither `disclose` nor this equality establishes secret possession. The input may remain private to the caller. ```compact import CompactStandardLibrary; export ledger admin: Bytes<32>; export ledger paused: Boolean; export circuit pause(caller: Bytes<32>): [] { assert(disclose(caller) == admin, "claimed admin"); paused = true; } ``` If this argument represents caller authority, separately enforce the protocol's reviewed signature or secret-possession relationship, bound to the intended key, message and replay domain. A supported enforced private-preimage check against preexisting ledger data on every reaching history suppresses this review; that check still relies on secrecy and adequate entropy. Additional arbitrary checks remain visible in the histories and prevent any sole-authorization inference. Later publication is a separate disclosure-analysis obligation; a suppressed review does not establish that a preimage remains secret throughout a protocol. Known review noise includes routing, public record consistency and mock identity checks. These legitimate patterns make the rule opt-in. A source-correct match is not a confirmed authentication defect, a concrete path or a deployed bypass. Constructor setup, optional/discarded/negative/after-effect comparisons, transformed inputs and self-written ledger echoes do not meet this contract. Old snapshots retain their initial revision. Scalars other than `Bytes<32>`, dynamic membership, general multi-secret/signature proofs and cross-entry protocol intent remain outside. The isolated exact pass observes all successful predicates, disables compressed fold/hash histories and retains the ordinary 40,000-step/256-path/50,000-value limits. It never reuses witness-only source-query certificates to prove this new obligation. Baseline-incomplete entries, wildcard selectors, missing predicate or invocation identities and exhausted evidence produce rule/entry-scoped incomplete diagnostics, separately from baseline completion. Consumer work is bounded to 200,000 applicability/decomposition/intersection checks. Constant-refined root inputs retain their unchanged identity. Conversely, a potential alternate preimage check with reconstructed/transformed equality dependencies cannot establish private status: bytewise equality may expose a whole preimage without equating its original scalar identity. Such entries are explicitly rule-incomplete; this consumer does not prove reconstruction secrecy. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line caller-supplied-ledger-equality -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/caller-supplied-ledger-equality.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # destructive-list-reset > Whole-list reset lacks a recognized same-revision count, empty-list or absent-slot acknowledgment. Canonical: https://nightshade.dicksonwu.xyz/rules/destructive-list-reset.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `destructive-list-reset` | | Severity | low | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | successful-histories, successful-predicates, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors destructive-list-reset ./.nightshade/node_modules/.bin/nightshade detector show destructive-list-reset ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/destructive-list-reset.md at v0.1.1. Availability: **opt-in review**; low severity / medium confidence. A whole persistent List is replaced with an empty List on a modeled successful nonconstructor history, without a recognized acknowledgment of that exact list revision. Recognized checks are a required live length equality to a caller/witness scalar or constant, a required empty-list check, or absence of that exact Map slot before initialization. ```compact export ledger changes: List; export circuit clearChanges(): [] { changes.resetToDefault(); } ``` For count-based acknowledgment, accept the caller's expected count and require it to equal the same live list's length. A saved immutable count can be asserted later in the same atomic proof, but an intervening append makes it stale for the reset revision. Wrong-list/key checks, ignored comparisons, optional checks and self-equality do not discharge this review. Constructor setup, known empty lists and exact absent-slot initialization stay quiet. Prefer pruning the acknowledged segment, or validate an epoch that is correctly maintained for this list. The rule does **not** infer arbitrary epoch/digest-to-list relationships. The corrected CFT epoch protocol and intentional purges are known review matches, so this rule stays opt-in. A count check alone is not proof of content identity, wallet durability or general concurrency safety. The engine preserves ordered writes, immutable dynamic-key identity, list revision and invocation sites. Unknown selectors, missing full predicates and exhausted matching allowances produce rule-scoped incomplete diagnostics. Unsupported baseline effects and budgets retain their existing incomplete result. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line destructive-list-reset -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/destructive-list-reset.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # inconsistent-keyed-state-guard > Consumer co-membership is checked on only some successful histories of a keyed insert. Canonical: https://nightshade.dicksonwu.xyz/rules/inconsistent-keyed-state-guard.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `inconsistent-keyed-state-guard` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | collection-observations, successful-predicates, successful-histories, state-writes, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors inconsistent-keyed-state-guard ./.nightshade/node_modules/.bin/nightshade detector show inconsistent-keyed-state-guard ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/inconsistent-keyed-state-guard.md at v0.1.1. Availability: **opt-in** with `--detectors inconsistent-keyed-state-guard`. Severity: **info**. Confidence: **high** for the structural observation. No policy required. The rule reports a final keyed insertion reached by some successful histories with a prerequisite membership check and others without it. A downstream entry must require both collections to contain the same exact key on every modeled successful history. Collection identity comes from resolved ledger declarations; collection names and assertion messages do not affect matching. This is a review obligation. Consumer checks do not prove that surplus entries are invalid. Intentional preauthorization or independent storage may explain the pattern. Findings leave invariant intent, cross-transaction feasibility and exploitability unproven. Confirm the application's intended relationship before requiring membership on every successful insertion. Analysis schedules one shared pass of exact successful histories, all predicates and ordered collection observations, including helper calls and cached transfers. Whole entries form dependency components through every canonical ledger root they may read or write, including ordinary key, control and value dependencies. Resolved source bodies, helper closures and zero-iteration callbacks participate. Every entry in a component containing Map/Set membership or insertion is included, even when that entry only removes an element or reads ordinary state. Unchanged assertions after an insertion still constrain its atomic success. Only unchanged, preexisting revision-zero prerequisite receivers are supported. Any prerequisite-root mutation or later target-root mutation prevents a finding. Map lookup alone does not establish the consumer relationship in this version. Unknown required keys, unsupported Boolean relations, incomplete histories or exhausted budgets produce diagnostics. These gaps never establish a clean rule result. A resolved absence of reachable Map/Set membership and insertion establishes not-applicable coverage without a dedicated collection-history observation pass. Resolved callback and helper edges participate in this bounded certificate. Unknown callable bodies, unknown external-contract effect scope or unfinished dependency traversal prevent all disjointness certificates and diagnose. Excluded entries and component dependencies are revalidated before relation analysis; Program.entries is never changed. Preparation and detector traversal work appear in ruleObservationWork metrics and consume the shared observation work/value allowance. Complete relevant histories remain required for every entry in the related component. A completed component can report beside an incomplete disjoint component. Unrelated branches inside a writer still make that whole entry incomplete; partial histories are never sliced into completed relation evidence. Shared work/value exhaustion can withhold proof even for previously completed histories. The independent baseline scan and overall report still retain their analysis gaps. Unscoped engine issues are conservatively associated with all incomplete components; these scopes do not identify an exact failure origin. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line inconsistent-keyed-state-guard -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/inconsistent-keyed-state-guard.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # mutually-exclusive-terminal-payout > Terminal payout remains reachable after a mutually exclusive one-time milestone. Canonical: https://nightshade.dicksonwu.xyz/rules/mutually-exclusive-terminal-payout.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `mutually-exclusive-terminal-payout` | | Severity | high | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | runtime-operations, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors mutually-exclusive-terminal-payout ./.nightshade/node_modules/.bin/nightshade detector show mutually-exclusive-terminal-payout ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/mutually-exclusive-terminal-payout.md at v0.1.1. Availability: **opt-in state-machine/effect review**, no policy required. Severity/confidence: **high/medium**. The rule finds a sibling one-time milestone transition (a represented Boolean false-to-true write) and a timeout/refund/release-style exported circuit that performs a canonical token payout and terminal-state write without reading the milestone state. It recognizes standard-library send lowering and reports the user call site. This is a cross-entry continuation review: censorship assumptions, commercial policy and runtime asset custody remain unproved. An application may intentionally allow the payout independently of a sibling milestone, or may use the state solely for off-chain coordination; either can produce a valid review match. The rule compares source-level entry effects. It does not prove transaction ordering, simultaneous reachability, custody loss, or that the milestone is the application's intended completion condition. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line mutually-exclusive-terminal-payout -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/mutually-exclusive-terminal-payout.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # re-initialization > Opt-in review of initializer-named entries with a state-changing second invocation. Canonical: https://nightshade.dicksonwu.xyz/rules/re-initialization.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `re-initialization` | | Severity | low | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | consecutive-invocations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors re-initialization ./.nightshade/node_modules/.bin/nightshade detector show re-initialization ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. An exported initializer can overwrite state again because it has no one-time guard. Full example: https://nightshade.dicksonwu.xyz/examples.md#re-initialization ```compact import CompactStandardLibrary; export ledger payload: Field; export circuit initialize(value: Field): [] { payload = disclose(value); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc LOW — Initializer has a modeled state-changing second invocation [re-initialization] vulnerable.compact:3:1 3 | export circuit initialize(value: Field): [] { payload = disclose(value); } | ^ initialize has two consecutive modeled successful invocations from constructor/default storage, with fresh inputs and a potentially different surviving value in payload after the second invocation. Review whether this entry is intended to run only once; its name alone does not establish that requirement. Call path: initialize Remediation: If initialization must run once, require the pre-initialized state and preserve its transition on every successful invocation. Review intentional reconfiguration separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Guard the initializer with a one-time flag. ```compact import CompactStandardLibrary; ledger done: Boolean; export ledger payload: Field; export circuit initialize(value: Field): [] { assert(!done, "already initialized"); done = true; payload = disclose(value); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/re-initialization.md at v0.1.1. Availability: **opt-in**; no policy required. Severity **low**, confidence **low**. Explicit detector selection replaces the default set. Owned example: the compiler-qualified [fixture](#example-1) allows an initializer-named entry to replace stored payload. The [correction](#example-2) requires the old `done` flag to be false and retains its true update. Review whether configuration is intended to be set once; recommendation: enforce that flag invariant when it is, or document intentional reconfiguration. Opt-in, low severity and low confidence. From a built source checkout, use: `node dist/src/cli.js scan examples/review/contract.compact --detectors re-initialization`. This review selects exported circuit declarations named `initialize`, `initializer`, or either name followed by an underscore suffix, that transitively write storage. It evaluates actual modeled construction/default storage, then two calls to that entry with fresh parameters and witness identities. A finding requires two modeled successful calls and a potentially different surviving ledger value after the second. Allocation IDs, revisions and temporary writes alone are insufficient. ```compact import CompactStandardLibrary; ledger configured: Field; export circuit initialize(value: Field): [] { configured = disclose(value); } ``` If `configured` was intended to be set once, a repeated initialization could replace the application's configuration. The finding does not prove that intention, concrete path feasibility, deployed reachability or exploitability. Intentional reconfiguration is a known false-positive shape. Naming is candidate evidence only; this is why the rule is opt-in and low confidence. For one-time behavior, assert the old initialization flag and preserve its update on every successful path. A late assertion on the saved old flag is also effective under the modeled atomic semantics. Setting and then restoring the flag does not establish one-time behavior. An idempotent write of the same final value stays quiet. The analysis retains storage, revisions, collection facts and scalar constraints across calls. It clears invocation-local guards, environments, call counters and effect histories. Historical private dependencies retain their original invocation; they do not become fresh caller evidence or certified trusted storage. Sequence assertions never contribute to the ordinary `impossible-assertion` rule. Ordinary entry analysis and the sequence share the existing per-entry step budget; retained first histories/pairs and abstract values also remain bounded. Exhaustion is incomplete. Transaction/context effects such as Kernel operations and coin qualification are not carried across calls. Counter scalar contents, zero updates and bounded net offsets from fixed checked updates are compared across calls. Other surviving ADT contents remain unsupported. Either boundary reports explicit incomplete diagnostics and no initialization finding for that entry. A guarded initializer that has no successful second call needs no final ADT-content comparison. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/re-initialization.compact`). ```compact import CompactStandardLibrary; export ledger payload: Field; export circuit initialize(value: Field): [] { payload = disclose(value); } ``` #### Example 2 Correction (source: `tests/corpus/safe/re-initialization.compact`). ```compact import CompactStandardLibrary; ledger done: Boolean; export ledger payload: Field; export circuit initialize(value: Field): [] { assert(!done, "already initialized"); done = true; payload = disclose(value); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line re-initialization -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/re-initialization.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#re-initialization) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # resettable-list-nonce > Canonical shielded coin nonce derives solely from a selected ledger List length that another exported entry can reset. Canonical: https://nightshade.dicksonwu.xyz/rules/resettable-list-nonce.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `resettable-list-nonce` | | Severity | low | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | canonical-mint-observations, completed-entries, cross-entry-state-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors resettable-list-nonce ./.nightshade/node_modules/.bin/nightshade detector show resettable-list-nonce ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 4/4 | 4/4 | 4/4 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/resettable-list-nonce.md at v0.1.1. Availability: opt-in. Severity: low. Confidence: high. Whole-root or identical literal selectors establish the same storage region. Dynamic Map selectors establish only may-overlap: the finding does not equate independent wildcard reads or assert that callers choose equal selectors. The review identifies a source that cannot serve as a monotonic extent across potential resets. Transaction feasibility, actual nonce recurrence, authorization intent, secret compromise and cryptographic attacks remain unproved. The consumer uses immutable query and native invocation snapshots, never variable names or a union of ledger dependencies. Caller nonce inputs, independent Counters, length used only as an amount, distinct literal selectors, aborted resets and local namesake helpers do not establish this relationship. Generic arithmetic, unknown seeds, decreasing pop operations and arbitrary crypto consumers are outside this initial contract. The informational companion [`resettable-memo-nonce-review`](https://nightshade.dicksonwu.xyz/rules/resettable-memo-nonce-review.md) adds a separate, narrower paired consumer observation for an exact selected recipient List and direct evolved payload append. It preserves this coin rule's findings and does not infer the stored payload's cryptographic role. Coin-only quiet controls do not establish memo uniqueness. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line resettable-list-nonce -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/resettable-list-nonce.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # resettable-memo-nonce-review > Stored recipient List payload and canonical coin nonce both evolve from the same resettable selected List extent. Canonical: https://nightshade.dicksonwu.xyz/rules/resettable-memo-nonce-review.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `resettable-memo-nonce-review` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | canonical-mint-observations, memo-append-observations, completed-entries, cross-entry-state-writes | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors resettable-memo-nonce-review ./.nightshade/node_modules/.bin/nightshade detector show resettable-memo-nonce-review ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 7/7 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/resettable-memo-nonce-review.md at v0.1.1. Availability: opt-in. Severity: info. Confidence: high. The initial scope is `Map, List>>`. The selected immutable key must equal the active account recipient's represented `ZswapCoinPublicKey.bytes`, through source operands or required successful equalities. Exact immutable lookup operands identify the source and destination within a history. A shared wildcard storage path never establishes their equality. Dynamic keys in separate entry histories establish only reset may-overlap; distinct literal reset selectors do not qualify. Replacements proven to target an absent slot or already-empty current List do not establish a restart; unknown initial storage is not assumed empty. An acknowledged nonzero count can still reset the extent and remains in scope. Select the rule explicitly: ```json {"version":1,"detectors":["resettable-memo-nonce-review"]} ``` No memo or encryption purpose is inferred from a List name or stored bytes. The finding states that the same resettable extent supplies both a canonical coin nonce and a directly stored evolved payload. Its protocol role requires review. An opaque payload does not represent memo construction or encryption use. An arbitrary stored hash, encoded index, nonce identifier or marker does not establish the paired relation. Fresh seeds, mixed/arithmetic indices, transformed payloads, noncanonical namesakes, another append receiver, different source revisions, exclusive histories and aborted resets do not qualify. Root Lists, nested Maps, contract recipients and unconstrained recipient relations are outside this narrow review. Quiet output concerns this paired relation only. In particular, a fresh coin nonce alongside a resettable length-derived stored payload is quiet because one consumer is independent; it does not establish memo uniqueness. An independent Counter used for both consumers avoids this paired resettable-length relationship. The rule does not establish actual recurrence, successful transactions, one-time pad use, encryption/decryption, confidentiality impact, authorization intent or production implementation correspondence. Use of a resettable extent is not by itself proof that a stored value requires security randomness. Severity remains informational and default activation is unchanged. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line resettable-memo-nonce-review -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/resettable-memo-nonce-review.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # shared-module-once-gate > Distinct importing module wrappers expose one canonical false-guard then true-write Boolean gate. Canonical: https://nightshade.dicksonwu.xyz/rules/shared-module-once-gate.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `shared-module-once-gate` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | resolved-model, canonical-module-identities | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors shared-module-once-gate ./.nightshade/node_modules/.bin/nightshade detector show shared-module-once-gate ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 1/1 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shared-module-once-gate.md at v0.1.1. Availability: **opt-in** with `--detectors shared-module-once-gate`. Severity: **info**. Confidence: **high** for the resolved source fact. Two distinct importing module instances expose direct wrappers calling the same canonical gate. The supported gate body consists exactly of an assertion that a Boolean ledger flag is false followed by an assignment of true to that flag. The assertion message must be parser-confirmed literal data; every operand has an exact supported shape. Wrappers and gates accept no arguments and return []. Resolved module, import and call identities distinguish shared gates from separate instances. No names or assertion messages establish initialization intent. A successful gate write contradicts its next false-state guard unless storage is reset. This does not prove an actual cross-transaction failure, independent initialization intent, or deployed compiler behavior. Intentional shared initialization receives the same review finding. Multiple aliases of a single wrapper module are quiet because they do not create distinct importing modules. Distinct compiler path/module identities remain distinct even when physical parsing shares bytes. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line shared-module-once-gate -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/shared-module-once-gate.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # write-only-ledger > Ordinary ledger Cell is explicitly written but has no Compact source read in the compilation unit. Canonical: https://nightshade.dicksonwu.xyz/rules/write-only-ledger.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `write-only-ledger` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / State and collections | | Engine facts used | resolved-model, ledger-read-write-usage, bounded-source-absence | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors write-only-ledger ./.nightshade/node_modules/.bin/nightshade detector show write-only-ledger ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 1/2 | 1/2 | 0/0 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | synthetic-regressions.json / write-only-ledger-70 | corrected | [3] to [3] | control hit | | synthetic-regressions.json / write-only-ledger-70 | lookalike | [3] to [3] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/write-only-ledger.md at v0.1.1. Availability: **opt-in**; no policy required. Severity **info**, confidence **high** for the source read/write observation. Select with `--detectors write-only-ledger`. Public ledger fields commonly serve DApps and indexers without a Compact source read. The corpus confirms source facts, not actionable dead state; default promotion requires a review showing that most matches are actionable. Reports an ordinary Cell ledger field with explicit source writes and no source read in the analyzed Compact compilation unit. Initialization or later writes can make a declaration appear used while circuit logic ignores its stored value. This extends `unused-declaration`, which treats mutation targets as references. ### Example and review scenario For example, a configurable role can be stored while its getter returns a constant: ```compact sealed ledger administratorRole: Bytes<32>; constructor(role: Bytes<32>) { administratorRole = disclose(role); } export circuit getRoleAdmin(): Bytes<32> { return default>; } ``` Review whether the getter should return the setting. This detector covers the no-read subset; reading that field in another circuit withholds a finding even if the getter still ignores it. ### Recommendation and limitations Read the stored value where its circuit behavior is intended. Retain intentional off-chain metadata and document its consumers. Off-chain indexers, wallets, TypeScript ledger readers and external application logic are outside this scan; the finding does not establish useless storage, a security defect, or that writes can safely be deleted. All represented helper and callback bodies count, including source-excluded paths, zero-iteration callbacks and functions not reachable from an entrypoint. Reads through snapshots, arguments, explicit methods and projections count. Native ADTs such as Counter and Map are excluded. One finding groups concrete canonical instances of the same declaration; any represented instance read withholds it. Same names in distinct declarations do not merge. Unbound generic/module bodies retain semantic instance and include context; one instantiated sibling cannot certify another body's read absence. Defining bindings distinguish unrelated same-name fields, and unknown references/import aliases are screened conservatively. Uncertain source evidence or missing bodies is explicitly rule-scoped incomplete, not a certified absence. Work/depth exhaustion discards the pass's findings and reports incomplete; its allowance is separate from other informational source rules and baseline transfer completion. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line write-only-ledger -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/write-only-ledger.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#state-and-collections) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # default-recipient-or-owner > A successful value output or pinned Ownable update uses a known default active address. Canonical: https://nightshade.dicksonwu.xyz/rules/default-recipient-or-owner.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `default-recipient-or-owner` | | Severity | medium | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | all-predicates, runtime-operations, state-writes, constants, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors default-recipient-or-owner ./.nightshade/node_modules/.bin/nightshade detector show default-recipient-or-owner ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/default-recipient-or-owner.md at v0.1.1. Availability: **opt-in**; severity **medium**, confidence **high** for the known active address. Destination intent and concrete feasibility require review. ### Description, example and scenario ```compact sendUnshielded(color, 1, right(default)); ``` The selected recipient is an all-zero 32-byte address at a modeled successful output. A nonzero check on an inactive Either payload does not validate that recipient. The rule also checks the final owner write in the byte-authenticated, pinned OpenZeppelin Ownable module. It excludes that module's explicit `renounceOwnership` path and a zero owner overwritten before successful completion. ### Recommendation Validate the active destination before use. Reserve zero destinations for an explicit, documented burn or authority-removal path. Ownership validation does not by itself establish caller authorization. ### Evidence and known false positives Exact transaction output operands and owner writes retain their individual history, selected tag and invocation sites. Bounded immutable equality projection includes aggregate leaves and later atomic assertions; it never borrows constraints from another history, ledger revision or wildcard region. Direct authenticated owner assignments are included. Unknown tags/bytes are not inferred to be zero; inactive defaults, known zero-amount outputs, rejected histories, unrelated ledger sentinels and namesake application routines are quiet. Imported module trust uses pinned source hashes and dependency identities, rather than a filename or name. **Intentional burns, including `shieldedBurnAddress`, are known review matches.** Custom ownership protocols, commitment-derived identities, default addresses with unknown tags, cross-invocation setup and arbitrary recipient encodings are outside the rule. Constructor output operations are reviewed; zero setup sentinels alone are not security evidence. Exact-observation exhaustion is entry/rule-scoped incomplete and preserves baseline analysis; a quiet incomplete rule is not clean. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line default-recipient-or-owner -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/default-recipient-or-owner.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # exact-balance-threshold > A threshold-only assertion uses the exact unshielded balance getter instead of its comparison API. Canonical: https://nightshade.dicksonwu.xyz/rules/exact-balance-threshold.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `exact-balance-threshold` | | Severity | info | | Confidence | high | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | resolved-source, canonical-stdlib-calls, local-result-uses | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors exact-balance-threshold ./.nightshade/node_modules/.bin/nightshade detector show exact-balance-threshold ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/exact-balance-threshold.md at v0.1.1. Availability: **opt-in**. Severity **informational**, confidence **high** for the resolved source relationship. Select with `--detectors exact-balance-threshold`. Compact's `unshieldedBalance(color)` fixes the queried balance to its value at transaction construction. Application requires that exact value to remain the same, even when a threshold would still hold. The comparison helpers record the comparison instead. This distinction is documented in the pinned standard library and verified in owned compiler output on five supported compiler profiles. ### Example and review scenario ```compact assert(unshieldedBalance(disclose(color)) >= disclose(amount), "balance"); ``` If only the lower bound matters, consider: ```compact assert(unshieldedBalanceGte(disclose(color), disclose(amount)), "balance"); ``` A changing contract balance can make the first transaction depend on more than its stated threshold. This finding does not demonstrate a failed transaction, funds loss, missing funding, or deployed impact. Exact balance coupling can be intentional; review it before changing the API. ### Matching and recommendation The rule recognizes the canonical getter directly or through immutable local identity aliases, disclosure and identity casts. Exactly one direct threshold assertion must be its only terminal source use, and the bound must fit the comparison helper's Uint<128> parameter. Reversed operands select the corresponding helper. Canonical import aliases work; application namesakes do not. Other numeric uses, equality/reconciliation, multiple bounds, closure captures, computed values and retained snapshots withhold the finding. Even a dead-source use conservatively retains the getter. Arbitrary helper forwarding, parameters passed between circuits, compound conditions and runtime reachability are outside this source matching contract. Entry-reference reachability includes syntactic branches and zero-iteration bodies; it is not proof of execution. Use the suggested comparison helper only when exact construction/application balance equality is unnecessary. Preserve the same color and amount, and check other validation and transaction effects. The getter and comparison APIs all refer to the invocation's initial balance, not a running total after sends, receives or mints. ### Evidence and limits Owned realistic Counter positive/corrected/lookalike mutations retain the original increment and notices. Getter-threshold / comparison-helper / exact-equality controls compile on 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0 and 0.35.0. Emitted getters return the numeric ledger-query result; the corrected helper performs the less-than operation inside the ledger query and returns a Boolean. Reference: Compact 0.34.0 source `1f671fc27818df2b2676b3a97f85b2b821756243`, `doc/api/CompactStandardLibrary/exports.md:961-969` and `compiler/standard-library.compact:324-340`. The pinned 0.31.1 source `0da5b0452eb0c1053d42418bf34b12cc29c7d63e` documents the same distinction. These are reference/compiler facts, not independently labeled application bugs. Missing front-end evidence and baseline resource exhaustion remain explicit. The bounded source query discards its partial result on exhaustion and marks this rule incomplete independently of baseline analysis. No new engine, budget increase, symbolic execution, runtime evaluation or exploit confirmation is introduced. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line exact-balance-threshold -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/exact-balance-threshold.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # field-arithmetic-wraparound > A directly published Field operation on preserved unsigned quantities may wrap without a proved bound. Canonical: https://nightshade.dicksonwu.xyz/rules/field-arithmetic-wraparound.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `field-arithmetic-wraparound` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | resolved-types, numeric-operands, successful-predicates, public-sinks | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors field-arithmetic-wraparound ./.nightshade/node_modules/.bin/nightshade detector show field-arithmetic-wraparound ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/field-arithmetic-wraparound.md at v0.1.1. ### Description This rule reports a directly published Field `+`, `-` or `*` expression when an operand preserves a nonconstant Uint value through explicit conversion or implicit arithmetic coercion and the successful transaction does not prove that the unreduced arithmetic stays within the Field range. Compact Field arithmetic reduces modulo the field; performing a quantity operation in Field can bypass the rejection behavior of checked unsigned arithmetic. ### Example and scenario ```compact export circuit decrease(amount: Uint<64>): [] { const previous = balance as Uint<64>; balance = disclose((previous as Field) - (amount as Field)); } ``` When the amount exceeds the previous quantity, Field subtraction can publish a large residue instead of rejecting underflow. Prefer checked Uint subtraction before widening, or assert `previous >= amount` on the same immutable operands. A later assertion on that same successful transaction also protects an earlier atomic write. A guard on replacement storage, another Map lookup, or another invocation of the same arithmetic helper does not protect these operands. ### Evidence and limitations The shared engine assigns deterministic result identities only from the exact operator and immutable operand identities/constants; unavailable identities remain fresh. It retains immutable shallow operator operands, value-preserving Uint conversion evidence and conservative integer envelopes. Same-pair orders, scalar equality aliases, successful checked-cast domains on the same immutable result, inherent ranges of proven scalar equality aliases, and excluded interval endpoints can discharge the rule. Cast domains protect earlier writes and uncast aliases of that result; a different result or exclusive history cannot borrow them. Domains are bounded at 256 per history and charged against the shared abstract-value budget. Addition/multiplication are safe when their unreduced maximum is below the Field modulus. A checked result cast only discharges wrapping residues that are all outside the successful result domain: a cast often rejects small-Uint subtraction underflow, but addition/multiplication may wrap to small values that pass it. Only successful histories contribute findings; earlier writes remain observable when later overwritten. Findings group effects at the same operation site and entry, without sharing guards between histories or helper invocations. An exported return is an application output, not necessarily public ledger storage. This is a bounded quantity-conversion rule, not general arithmetic verification. Constant-only operations and generic Field-only algebra stay quiet. Nested operator origins, arithmetic used only inside a hash or condition, arbitrary quantity intent and algebraic safety identities are outside the shallow contract. A pure Field balance/amount pair without a preserved Uint conversion is therefore not covered. A potential interval wrap does not prove a feasible input or a vulnerability. Intentional modular use of Uint-derived operands may match and should receive a reasoned suppression after review. Exact arithmetic and all successful predicates are required. Unsupported evidence produces `arithmetic-evidence-unavailable`, `arithmetic-domain-incomplete` or `arithmetic-constraints-incomplete`; review allowance exhaustion produces `arithmetic-review-budget` or `arithmetic-domain-budget`. The allowance is 200,000 work units, in addition to normal path/step/value budgets; exhaustion remains incomplete. The structural applicability scan is bounded and conservatively enables observation if exhausted. Exact arithmetic observation bypasses specialized compressed hash/fold histories, so corpus completion must be measured when this rule is enabled. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line field-arithmetic-wraparound -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/field-arithmetic-wraparound.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # inconsistent-access-control > An exported writer omits the caller-check convention required by a strict majority of its peers. Canonical: https://nightshade.dicksonwu.xyz/rules/inconsistent-access-control.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `inconsistent-access-control` | | Severity | medium | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | successful-predicates, all-private-predicates, state-writes, runtime-operations, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors inconsistent-access-control ./.nightshade/node_modules/.bin/nightshade detector show inconsistent-access-control ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/inconsistent-access-control.md at v0.1.1. Availability: **opt-in** with `--detectors inconsistent-access-control`; no policy required. Severity **medium**, confidence **low**. Explicit selection replaces the default detector set. This is an inferred code convention requiring review, not a claim of an exploitable missing privilege check. Review the intended policy for each sibling entry; restore a required check or document an intentional public exception. The intended rule identifies a code convention: a strict majority of distinct exported writers of the same declared ledger field, or callers of the same modeled value-moving operation, require a caller-authentication relationship, while another successful writer does not. No application policy or security meaning inferred from names is sufficient. At least two guarded exported entries must support a majority; repeated writes, helper calls and aliases of one entry cannot manufacture it. Required evidence comes from actual successful predicates and ordered effects. Only histories reaching the relevant effect enter its guard intersection. An ignored comparison, rejected history, constant-only validation or same-named lookalike helper cannot supply caller authentication. Private preimages constrained to public data must not supply secret authentication, including constraints before hashing or after the effect. Genuine alternate authentication must not be labeled an omission merely because it uses a different helper, key or source kind. An atomic late guard may constrain successful completion; its later position remains visible. Constructor writes do not enter the exported-operation majority. Incomplete potential writers prevent universal claims for their affected group. Unknown effects and exhausted decoding/intersection budgets must remain explicitly incomplete, without partial convention findings. Grouping writes to a declared collection is not proof that different dynamic keys address the same cell. ### Supported evidence and limitations An authentication convention is a required equality between a definite preexisting ledger value and either a direct hash of one private input, or an exact raw witness input. The hash may contain fixed aggregate prefixes or repetitions of that same input. Witness and entry-parameter preimages support the same convention. Different private inputs are not equated across entries: the shared key is the trusted ledger origin, hash primitive and relationship kind. A raw equality is explicitly weaker; it does not suppress an omitted secret-preimage convention. The check intersects conventions across every successful reach of the target by each exported entry. A strict majority, including at least two entries, must share one convention. Another private-preimage check can satisfy the minority writer even when its key or helper differs. Branch-local checks and ignored comparisons do not become required checks. Whole-history public equalities, including aggregate components and late assertions, disqualify a claimed secret preimage. Predicates from mutually exclusive histories are never combined. Targets are declared ledger fields or actual modeled transaction operations: `mintShielded`, `mintUnshielded`, `claimZswapCoinSpend`, `claimUnshieldedCoinSpend`, `createZswapInput` and `createZswapOutput`. Nested helper names alone cannot establish these effects. Findings preserve the actual writer invocation and sibling predicate call sites and effect positions. A collection field groups its writers; it makes no must-alias claim about dynamic keys. The bounded applicability walk only proves that a convention is impossible or identifies potential incomplete writers. Dead syntactic writers do not enter the majority denominator. The rule requires `predicateScope: "all-private"` exact facts. Default and experimental Counter dispatch use whole-program inapplicability to preserve existing correlated admission; a possible convention requires genuine exact fallback. There is no per-entry no-witness certificate for this rule. Applicability is bounded to 20,000 operations; predicate decoding/publicness and intersection share a separate 1,000,000-operation allowance with bounded aggregate expansion. Exhaustion returns diagnostics and no partial convention findings. Signature/protocol validity, arbitrary transformed or multi-source preimages, external caller trust and cross-transaction reachability are not proved. Authentication through a relationship outside the documented patterns can look like an omission. Two sibling operations using unrelated trusted ledger origins do not establish one shared convention. Deliberately public reset, mint or transfer operations can match; the compiler-valid intentional-public control explicitly expects that false-positive shape. Review the access policy before adding a guard or suppressing the finding. ### Example and correction ```compact import CompactStandardLibrary; export ledger owner: Bytes<32>; export ledger stored: Field; witness secret(): Bytes<32>; circuit caller(): [] { assert(persistentHash>(secret()) == owner, "owner"); } export circuit first(next: Field): [] { caller(); stored = disclose(next); } export circuit second(next: Field): [] { caller(); stored = disclose(next); } export circuit missing(next: Field): [] { stored = disclose(next); } ``` `missing` is the minority writer. If it should follow the sibling policy, call `caller()` before its write. If it is deliberately public, document that exception. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line inconsistent-access-control -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/inconsistent-access-control.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # merkle-insert-without-dedupe > Review sequential bounded Merkle insertion without exact surviving duplicate prevention. Canonical: https://nightshade.dicksonwu.xyz/rules/merkle-insert-without-dedupe.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `merkle-insert-without-dedupe` | | Severity | info | | Confidence | medium | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | canonical-insertion-snapshots, collection-observations, all-predicates, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors merkle-insert-without-dedupe ./.nightshade/node_modules/.bin/nightshade detector show merkle-insert-without-dedupe ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 1/2 | 0/0 | 0 | Deviations recorded for this rule: | Case | Kind | Expected to observed lines | Issue | | --- | --- | --- | --- | | synthetic-regressions.json / merkle-insert-without-dedupe-39 | lookalike | [11] to [11] | control hit | These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-insert-without-dedupe.md at v0.1.1. Availability: **opt-in**; severity **info**, confidence **medium**. This rule reviews sequential native `MerkleTree` and `HistoricMerkleTree` `insert`/`insertHash` calls without exact duplicate-prevention evidence. A bounded tree has a finite number of slots; review whether repeated values should consume more than one. Indexed replacement and constructor setup are outside this rule. ```compact assert(!seen.member(value), "already inserted"); tree.insert(value); seen.insert(value); ``` The analyzer requires an enforced preceding absence check on the actual inserted value, plus a matching insertion into that same persistent collection which survives completion. Remembering before the tree insert is also supported. Required immutable equality can connect aliases and nested receiver keys. Ignored or unrelated checks, erased records and checks borrowed from an exclusive history do not suppress review. Reusing one check for another potentially aliasing tree insertion remains a review candidate. If duplicates are invalid, use a persistent dedupe collection and retain its record. If repeated leaves are intentional, document that contract and optionally disable this informational review. External uniqueness invariants, alternate dedupe schemes, or independent tree operations can also produce review candidates. This rule does not establish repeated-insert feasibility, capacity exhaustion, denial of service, replay or deployed impact. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line merkle-insert-without-dedupe -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/merkle-insert-without-dedupe.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # nullifier-check-without-insert > Required collection absence lacks a definite surviving insertion on a state-changing history. Canonical: https://nightshade.dicksonwu.xyz/rules/nullifier-check-without-insert.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `nullifier-check-without-insert` | | Severity | medium | | Confidence | low | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | collection-observations, successful-predicates, state-writes, completed-entries | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors nullifier-check-without-insert ./.nightshade/node_modules/.bin/nightshade detector show nullifier-check-without-insert ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Verified example Synthetic example from the proof run of the released CLI. The circuit checks that an identifier is unused but never inserts it into the used set. Full example: https://nightshade.dicksonwu.xyz/examples.md#nullifier-check-without-insert ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); accepted = disclose(id); } ``` Output (exit code 1): ```text $ nightshade vulnerable.compact --config config.json --compiler /path/to/compactc MEDIUM — Required absence lacks a surviving matching insertion [nullifier-check-without-insert] vulnerable.compact:7:11 7 | assert(!used.member(disclose(id)), "fresh"); | ^ accept has a modeled successful state-changing history requiring absence from used, without a definite surviving insertion of that exact value/key into the same collection. Review whether this check is intended to consume a one-use identifier. Source: vulnerable.compact:7:11 Call path: accept Remediation: If this is a one-use identifier, insert the checked value/key into the same persistent collection on every successful history and retain it through transaction completion. Review intentional absence validation separately. Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 1 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Corrected: Insert the identifier into the used set. ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); used.insert(disclose(id)); accepted = disclose(id); } ``` Output (exit code 0): ```text $ nightshade corrected.compact --config config.json --compiler /path/to/compactc Semantic profile: compact-0.34.0-zkir2. Baseline analysis: complete; selected rules: complete. Rule coverage: 1 selected rule(s); 0 with incomplete entries. 0 finding(s), 0 suppressed, 0 baseline; 1/1 entrypoint(s) completed; analysis complete. Compiler validation passed. ``` Paths are shortened to the example folder. A quiet result shows that this rule stopped firing, not that the contract is secure. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 2/2 | 2/2 | 2/2 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/nullifier-check-without-insert.md at v0.1.1. Availability: **opt-in** with `--detectors nullifier-check-without-insert`; no policy required. Severity **medium**, confidence **low**. Explicit selection replaces the default detector set. ### Owned example and review scenario The compiler-qualified [fixture](#example-1) requires collection absence before changing state. If the application intends one-time consumption, the [correction](#example-2) retains an insertion in the same collection: ```compact assert(!used.member(disclose(id)), "fresh"); used.insert(disclose(id)); accepted = disclose(id); ``` Recommendation: first confirm nullifier intent, then consume that exact member/key on every successful relevant history and preserve the insertion. Absence checks used for ordinary collection administration need not consume a nullifier. ### Evidence and limitations A candidate is a modeled successful nonconstructor history that requires absence of an exact value/key in a ledger Set/Map and performs a persistent or canonical token effect, but does not leave that value/key inserted in the same collection. This is a structural replay-prevention review, not proof that the value is intended to be a nullifier or that another transaction can replay it. Read-only membership helpers and user namesakes do not establish a missing-consumption finding. The matcher must preserve the actual query Boolean and its value/receiver snapshots. Ignored queries and tautologies are not guards. Different keys, witness invocations, collection instances and stale aliases cannot supply insertion credit. Saved absence results and late atomic assertions remain meaningful; insert-then-remove/reset does not consume a key. Alternate successful paths and nested helper calls remain separate. Unknown overlap/equality must not invent proof of consumption. Unsupported effects and exhausted observation/decoding budgets must be explicitly incomplete, discarding partial rule findings after query exhaustion. The default engine now correlates repeated dynamic membership queries by exact receiver selectors, member operands and ledger revision, retaining the observation across local cleanup. It never identifies two reads merely by a wildcard region. The opt-in observations also retain immutable hash/commitment operands and the ordered query/write positions. Component equalities rebuild aggregate identities; bounded Boolean equality/negation propagation handles indirect absence guards. Inserts survive descendant value updates, but removal, reset or possible ancestor replacement revokes credit. Each operand traversal is bounded to 4,096 visits and charged to analysis work; rule matching shares a 1,000,000-work allowance. Any exhaustion discards partial rule candidates and emits an incomplete diagnostic. Read-only absence checks can be intentional for collection administration and need not consume a key. A match is a replay-prevention review prompt; it does not establish that the checked value is a protocol nullifier or that another transaction can replay an operation. ### Source examples These short regression examples are included here for installed-package readers. Rule-specific policy requirements and limits above still apply. #### Example 1 Fixture (source: `tests/corpus/vulnerable/nullifier-check-without-insert.compact`). ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); accepted = disclose(id); } ``` #### Example 2 Correction (source: `tests/corpus/safe/nullifier-check-without-insert.compact`). ```compact import CompactStandardLibrary; ledger used: Set; export ledger accepted: Field; witness token(): Field; export circuit accept(): [] { const id = token(); assert(!used.member(disclose(id)), "fresh"); used.insert(disclose(id)); accepted = disclose(id); } ``` ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line nullifier-check-without-insert -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/nullifier-check-without-insert.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [Verified example](https://nightshade.dicksonwu.xyz/examples.md#nullifier-check-without-insert) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # publicly-derived-guard-tag > A supplied tag is required equal to a hash derived from preexisting public ledger data and caller-supplied inputs before an effect. Canonical: https://nightshade.dicksonwu.xyz/rules/publicly-derived-guard-tag.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `publicly-derived-guard-tag` | | Severity | medium | | Confidence | medium | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | direct-hash-inputs, all-successful-predicates, exact-effect-histories | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors publicly-derived-guard-tag ./.nightshade/node_modules/.bin/nightshade detector show publicly-derived-guard-tag ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis. | Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete | | ---: | ---: | ---: | ---: | ---: | | 1/1 | 1/1 | 1/1 | 0/0 | 0 | No deviations were recorded for this rule. These are behavior checks on synthetic fixtures, not a precision or recall estimate. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/publicly-derived-guard-tag.md at v0.1.1. Availability: **opt-in**, no policy required. Severity/confidence: **medium/high**. Select with `--detectors publicly-derived-guard-tag`. The rule reports a raw supplied tag required equal to an exact native hash recipe containing definite preexisting public ledger data, with remaining ingredients limited to constants, unchanged caller-supplied parameter leaves and recursively supported native hashes. The comparison must precede a ledger or kernel effect on every modeled successful reach of that exact effect invocation. Findings group the guard site and entry, listing affected effects and separate history evidence. ```compact export ledger attestorKey: Bytes<32>; export ledger accepted: Counter; export circuit accept(message: Bytes<32>, tag: Bytes<32>): [] { assert(tag == persistentHash>>([attestorKey, message]), "tag"); accepted.increment(1); } ``` If this tag is intended to authenticate an attestor, hashing its public key and the supplied message does not verify a signature or secret possession. Use the protocol's reviewed verifier bound to the trusted signer and intended message. Other proofs can still provide authorization; this rule never establishes a sole gate, authentication intent, concrete feasibility or deployed vulnerability. **Caller-supplied does not mean public:** an entry parameter can remain private, and only its supplier is assumed to know it. A private witness ingredient or witness-dependent recipe/control excludes the match, including nested hashes. Intentional checksums and prototype mock attestations are known review shapes. They are why this rule is opt-in. A correct static match is not a confirmed authentication defect; source intent and other protocol proofs require review. Supported hashes are canonical `persistentHash`, `transientHash` and `keccak256`. Tag operands are unchanged scalar `Bytes<32>` or `Field` sources. Constants must have no private provenance: an assertion-refined witness is not a public literal. Exact preexisting ledger provenance is required; may-ledger dependencies, fresh caller-written keys, wildcard equality and a namesake hash do not suffice. An immutable old ledger snapshot can remain an ingredient after a later write. Optional/bypassed, ignored, negative, after-effect, return-only and constructor comparisons stay quiet. Arithmetic-derived parameter recipes and general custom crypto are outside this boundary. Entry-isolated exact observations retain all predicates and typed digest inputs under the existing 40,000-step/256-path/50,000-value limits. Values share the rule's pass allowance. Entries whose baseline semantics are incomplete remain explicitly unavailable for this rule, without an expensive duplicate attempt; this restriction is not a completion or absence certificate. Consumer recipe/intersection work is bounded to 200,000 checks per invocation; recursive recipe/Boolean traversal is limited to depth64 and immutable keys to 4,096 nodes/depth32. Missing predicate/invocation evidence, unsupported exact observations and exhaustion produce rule/entry-scoped incomplete diagnostics and discard that entry's partial findings. Baseline coverage and other rules' findings remain independent. No engine admission or budget is expanded. The family is grounded in Compact's witness/claimed-input trust boundary and documented public-data mock attestations; no execution or exploit reproduction is needed. Tests preserve instruction/reference and cached/uncached agreement, nested summary replay, guard alternatives, storage snapshots and checkpoint prefixes. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line publicly-derived-guard-tag -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/publicly-derived-guard-tag.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md) ===== # unasserted-security-result > Review predicate outcomes discarded before effects, persisted, or returned with an effect; security intent unknown. Canonical: https://nightshade.dicksonwu.xyz/rules/unasserted-security-result.html Release: Nightshade 0.1.1 (v0.1.1) | Field | Value | | --- | --- | | Rule ID | `unasserted-security-result` | | Severity | medium | | Confidence | varies | | Maturity | experimental | | Selection | Opt-in | | Policy intent | not required | | Default enabled | no | | Category | Other active opt-ins / Source structure and validation | | Engine facts used | resolved-model | | Release | v0.1.1 | ## Selection and scope Not selected by default. Select it with `--detectors` or the `detectors` list in nightshade.json. Either one replaces profile selection, so list every rule you want. ```sh ./.nightshade/node_modules/.bin/nightshade ./contracts --detectors unasserted-security-result ./.nightshade/node_modules/.bin/nightshade detector show unasserted-security-result ``` The first command runs only this rule; `--detectors` takes a comma-separated list. The second prints the rule's metadata from your installed version. Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental. Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope. ## Corpus checks The 0.1.1 proof run had no mapped synthetic corpus checks for this rule, so there are no measured results to show here. See [evaluation](https://nightshade.dicksonwu.xyz/evaluation.md#synthetic-corpus). ## Rule documentation From https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unasserted-security-result.md at v0.1.1. Opt-in, low-confidence review. Flags a comparison or canonical predicate discarded before a ledger write/send, persisted as data, or returned inside an aggregate after an effect without earlier enforcement of that exact predicate. A Boolean-returning predicate API is allowed. Recording a status can be intentional; the rule does not infer security intent from names. Uses resolved expressions, local aliases and separate branch states. Direct calls are supported; helper-mediated constraints are outside this review. Unsupported loops and exhausted traversal budgets produce diagnostics. ## Suppress a match If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters: ```compact // nightshade-disable-next-line unasserted-security-result -- Reason this match is intentional ``` Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See [configuration](https://nightshade.dicksonwu.xyz/configuration.md#suppress-an-intentional-match) for fingerprint suppressions and baselines. ## References - [Rule source document at v0.1.1](https://github.com/DicksonWu654/nightshade/blob/v0.1.1/docs/detectors/unasserted-security-result.md) - [Catalog entry in rules.json](https://nightshade.dicksonwu.xyz/rules.json) - [All rules](https://nightshade.dicksonwu.xyz/rules.md#source-structure-and-validation) - [Limitations](https://nightshade.dicksonwu.xyz/limitations.md)