Skip to main content

neutron-security

The package that decides whether ordinary app Motoko is allowed into a complete Neutron actor.

It defines one ordered policy, projected over two compiler paths:

PathWhere it runs
Packagingmopack, over every final module of an app being packed
Compilationneutron-compiler, over every reachable module before assembly

Both current paths use the same deterministic rule order. With the same policy and reviewed whitelist, the packager and install-time scan agree; an archive created under an older toolchain is still revalidated by the current compiler and can be rejected by a newer policy.

How the analysis works

Two views of the source are combined.

A Motoko-aware lexer preserves facts that the bundled simplified AST erases. It skips nested comments, strings, and character literals; distinguishes brace-based record extension from parenthesized call contexts; and reports source lines for diagnostics.

The AST is authoritative for what counts as an acquisition. Only dotted members and object-pattern fields are treated as name-based acquisitions — so renaming a privileged primitive during import or destructuring does not evade the policy, while harmless local names, type fields, and record-literal keys remain usable.

The two paths differ in how they combine these:

  • The browser compiler starts from a compact member inspection plus source-only facts. If the lexer sees a privileged spelling that compact facts do not explain, that single module falls back to full AST parsing. The spelling is a fallback trigger, not a finding.
  • The packager always parses the full AST and intersects readable text candidates with its authoritative findings.

What is checked

See Static checks for the complete rule list and the reasoning behind each one. In summary the policy blocks actor and shared-function references, raw inter-canister calls, cycle primitives, raw stable memory and Regions, certification APIs, the <system> capability, raw caller attributes, canister environment access, process-wide Candid limits, and raw timers.

Fixtures

The package ships allowed/ and disallowed/ sample Motoko files and a checker that runs the policy over both directories. The check command also scans core production source for app-specific imports, identities, methods, and retired vocabulary. The same fixture logic is covered by the package's test suite, and unexpected parser failures fail that suite rather than being silently tolerated.

One retained legacy fixture is an expected parser failure, because the obsolete form it contains is rejected before policy matching even begins.

The dump.ts utility prints the vendored compiler's parsed AST for one Motoko file, which is useful when diagnosing how a policy pattern sees that source.

The whitelist

Two identical hash maps live in neutron-scripts and neutron-compiler. They record exactly two reviewed pinned Motoko Core facades: Principal.mo and Runtime.mo.

The role of the whitelist is narrow and worth stating precisely: if a final module's content hash matches an entry, the dangerous findings recorded for that exact content are accepted. It does not trust a package name, and it does not trust other modules in the same package.

Random.mo is deliberately absent, because it embeds paid management-canister raw_rand access. Apps that need entropy declare the kernel randomness capability instead and receive a scoped handle with concurrency, result-size, lifecycle, and cycle-reserve enforcement.

The generator refuses to add any Core module other than those two.