Skip to content
Docs menu

How it works

Kratex runs inside your Node process. When your code or one of its dependencies does something sensitive (reads a file, opens a network connection, spawns a process), Kratex checks it against your policy at that moment and decides whether it proceeds.

inside the Node processstarted by kratex run
a dependency runs
net.connect("203.0.113.9:443")
Kratex patched net, so the call is intercepted before it opens
rule engine
built-in rules + your kratex.policy.json
decision
blockthe connection never opens
allowauditblockwould-block
Kratex patches fs, net, http, child_process, module, and process.env.

In-process guards

When you run kratex run node app.js, the CLI spawns Node with a preload attached via --import (Node 20.6+) or --require (older). The preload patches Node’s core APIs (fs, net, http, child_process, module, process.env) so any call into them passes through Kratex first.

Kratex enforces in-process, from JavaScript, because kernel-level mechanisms (eBPF, seccomp) lose the JavaScript call stack: the information Kratex needs to know which package made each call.

Caller-chain attribution

Kratex walks the call stack and tags each frame with the package that owns it. The owner nearest the call is the primary caller, and that is what a rule’s subject matches.

call stack at net.connect()top = nearest the call
node_modules/sketchy/dist/x.js:42
node_modules/sketchy/dist/y.js:11
sketchyprimary
node_modules/express/lib/router.js:88
express
src/server.js:3
your app
A rule’s subject matches the primary caller: sketchy (third-party).
Adjacent frames with the same owner collapse; the owner nearest the call is the subject.

So you can allow a network call from your own code but block the identical call from a dependency. See Policy authoring → Subject for how to target specific packages or source classes.

How rules become decisions

For every intercepted operation, the runtime evaluates all matching rules and keeps the single best match. More specific rules beat less specific ones; user rules beat built-ins at equal specificity. If nothing matches, the default is allow. Policy reference has the full ordering.

The matched rule’s effect.action is one of allow, audit, or block. What happens next depends on the policy’s mode:

  • enforce mode: block throws KratexPolicyViolation (error code ERR_KRATEX_POLICY) in the child, so the guarded operation never completes.
  • audit mode: block is demoted to would-block: the operation proceeds, an event records the violation. A small set of structural built-in rules (wallet reads, install-time network, self-propagation) fire hard even in audit mode. Demoting them would let the irreversible operation complete: the wallet is read, the credential leaves the machine.

A concrete flow

A third-party package tries to read ~/.aws/credentials:

  1. The patched fs.readFileSync intercepts the call.
  2. The caller chain identifies the third-party package as the primary owner.
  3. The built-in kratex.builtin.third-party-credential-read rule matches.
  4. Under enforce mode, the read throws KratexPolicyViolation and never returns the file contents.

The read also stamps the caller with a credentials exposure label: if that same package later makes a network call, the built-in kratex.builtin.third-party-exposed-outflow-network rule blocks it. Static scanners see code at rest; this chain (read, exposure, blocked outflow) happens at run time.