# 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<Bytes<32>>(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)
