Network and Access Runtime Control
narc.mp4
NARC is an eBPF-powered Linux security daemon that catches supply-chain attacks before they exfiltrate your secrets. It watches sensitive files (SSH keys, cloud creds, .env, kubeconfig, wallet data), taints any process that reads them, and blocks suspicious network egress from tainted processes — all locally, with no cloud dependency.
┌─────────────────────────────────┐
│ YOUR WORKSTATION │
│ │
~/.ssh/id_ed25519 ─┐ │ ┌───────────┐ │
~/.aws/credentials ─┼──▶ NARC │ WATCHLIST │ │
.env ───────────────┘ (eBPF) │ file_open │ │
│ └─────┬─────┘ │
│ │ read detected │
│ ▼ │
│ ┌───────────┐ │
│ │ TAINTED │ │
│ │ PROCESS │ ◀─── npm install│
│ └──┬────┬───┘ (malicious │
│ │ │ dependency) │
│ │ │ │
│ ▼ ▼ │
│ fork() connect() │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────┐ ┌────────────┐ │
│ │ CHILD IS │ │ RULES │ │
│ │ ALSO │ │ │ │
│ │ TAINTED │ │ ✓ allow │──┼──▶ api.github.com
│ │ (implicit)│ │ ✗ deny │──┼──✗ evil.example.com
│ └───────────┘ │ ? prompt │ │
│ └────────────┘ │
└─────────────────────────────────┘
A compromised npm package or pip dependency reads your ~/.aws/credentials and curls it to an attacker's server. This has happened — axios via plain-crypto-js, litellm via PyPI — and traditional tools miss it because the read and the exfiltration happen in separate steps.
NARC connects those steps. It taints the process on read, follows forks and derived files, and intercepts the outbound connection. You get a prompt before anything leaves your machine.
Narc lets you define a watchlist for:
- files: examples:
~/.aws/config,~/**/wallet.dat - network hostnames: example:
api.openai.com:443 - executables: example:
/usr/bin/curl
Any time a file, network hostname, or executable in your watchlist is read, requested, or run, Narc logs the event in the audit history. You can one-click create policies around these events to block requests or edit the ~/.config/narc/watchlist.yaml` directly.
Example ~/.config/narc/watchlist.yaml:
id is an optional field that narc will auto-generate if omitted. ids need to be globally unique
files:
# watch access to anything in ~/.ssh
- id: db6043af
path: ~/.ssh/
# deny reads from any executable to ~/.aws/credentials
- id: 008ccf64
path: ~/.aws/credentials
rules:
- id: 1
executable: '*'
decision: deny
enabled: true
# deny by default access to ~/.config/gcloud but allow the gcloud python CLI access
- id: 3da7a644
path: /home/victor/.config/gcloud/*
rules:
- id: 2
executable: *
decision: deny
- id: 3
executable: /home/victor/bin/google-cloud-sdk/platform/bundledpythonunix/bin/python3
decision: allow
network:
# block curl from making requests to github.com
- id: 308981da
destination: github.com:443
rules:
- id: e268d5b0
executable: /usr/bin/curl
decision: deny
# watch requests to registry.npmjs.org from any process
- id: 812ab543
destination: registry.npmjs.org:443
executables:
# Block nc from making any connections
- id: bb8d8f78
path: /usr/bin/nc
rules:
- id: 4b9a912e
resource: '*'
type: network
decision: deny
enabled: true
# block /usr/bin/cat from reading /tmp/1.txt
- id: 906778b8
path: /usr/bin/cat
rules:
- id: 7833ce9a
resource: /tmp/1.txt
type: file
decision: deny
enabled: true- File monitoring — eBPF LSM
file_openhook watches sensitive file reads - Taint propagation — taints flow to child processes and files written by tainted processes
- Network gating — eBPF LSM
socket_connecthook intercepts public connections from tainted processes - Hostname-aware rules — allow/deny/prompt policies per destination hostname
- Local web UI — live event stream, pending prompts, taint state, watchlist editing, policy management
- Zero trust, fully local — daemon on
127.0.0.1, all state on disk, token-authenticated UI
Start NARC in the foreground:
./narc startOn first run, NARC will request sudo once so it can apply the required Linux capabilities to the binary and restart itself. After that, the same binary should start without another privilege prompt. Narc will ask for a sudo password every time the binary is replaced or upgraded.
Useful commands if narc is running in the background:
# Show current narc status, including the local admin UI URL and token
./narc status
# Launch the local UI
./narc uiThe UI is served at http://127.0.0.1:8844. narc status and narc ui use a #token=... bootstrap URL, and the browser strips that fragment after load so the token only stays in memory for the session. The local auth token is stored at ~/.config/narc/auth_token.
Copy the binary anywhere on your system then make it executable:
# locally in your home dir
mv narc ~/bin/narc && chmod 755 ~/bin/narc
# install narc system wide
sudo install -m 755 ./narc /usr/local/bin/narcThen configure systemd, x11, .bashrc, hyprland, etc to run narc in the background.
# ~/.config/hypr/hyprland.conf
...
exec-once = ~/bin/narc startNARC stores its local state in ~/.config/narc/:
auth_token: local API/UI bearer tokenconfig.json: daemon settingswatchlist.yaml: file and network watchlist entriestaint-state.json: live and historical taint state plus derived watched files
The Watchlist supports wilcards and recursive globbing, so these are all valid:
~/.aws/credentials~/.azure/**~/**/.env
Note: The more recursive globs you have in the watchlist, the longer it takes for NARC to start.
The runtime is split into three pieces:
- eBPF programs enforce or observe file and network activity in-kernel.
- A Go daemon resolves process and hostname context, persists policy and taint state, and translates kernel events into operator-facing actions.
- An embedded static web app exposes prompts, events, settings, and policy management over a localhost-only API and WebSocket stream.
- Linux with kernel 5.7+.
- BPF LSM enabled:
CONFIG_BPF_LSM=yandbpfpresent in the active LSM list. - BTF available at
/sys/kernel/btf/vmlinux. - Go 1.22+.
clangandllvm(only needed forgo generate; pre-built BPF artifacts are checked in).setcap/getcapavailable for the capability bootstrap flow.
Build the daemon and embedded UI:
make buildRun the test suite:
go test ./...make buildrunsgo generate ./internal/bpf/before compiling.- The generated BPF artifacts are checked into the repository.
- A pre-built
vmlinux.hfrom the libbpf/vmlinux.h project (kernel 6.19, x86) is checked in. CO-RE ensures the compiled BPF programs work across kernel versions with BTF support. To regenerate from your running kernel instead:bpftool btf dump file /sys/kernel/btf/vmlinux format c > internal/bpf/vmlinux.h. - Static assets live in
web/static.