Rule

missing-role-bootstrap

An authenticated ShieldedAccessControl instance initializes but has no role-seeding route.

Release v0.1.1View Markdown

Specimen 17 of 96 · Audit-default ordinary rules

Severity
low
Confidence
varies
Maturity
experimental
Selection
Audit default
Policy intent
not required
Release
v0.1.1
Engine facts used
resolved-calls module-identities constructor-histories

Selection and scope#

Selected by the default audit profile, so an ordinary scan runs it.

Shell
./.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 detectedCorrected quietLookalike quietOther negative quietIncomplete
2/22/22/20/00

No deviations were recorded for this rule.

These are behavior checks on synthetic fixtures, not a precision or recall estimate. See evaluation.

Rule documentation#

From 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 for fingerprint suppressions and baselines.

References#