Rule

declared-secret-publication

Policy-declared secret information reaches a public sink through an unapproved transformation.

Release v0.1.1View Markdown

Specimen 35 of 96 · Policy-dependent rules

Severity
high
Confidence
medium
Maturity
experimental
Selection
Audit; needs policy
Policy intent
required
Release
v0.1.1
Engine facts used
private-provenance implicit-flows public-sinks privacy-policy

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.

Shell
./.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 detectedCorrected quietLookalike quietOther negative quietIncomplete
3/33/32/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/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 forwards secret() through a helper to a ledger write. Its policy is:

JSON
{ "secrets": [{ "witness": "secret" }] }

Place this object under policies in the configuration. The correction 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 for fingerprint suppressions and baselines.

References#