← Back to list

Your eBPF Security Monitor Is Running. It’s Also Blind.

How writable BPF maps become a telemetry trust boundary weakness in Falco, Tracee, and Tetragon

Azizcan Dastan · 2026-05-27 14:30 · 5 claps · 3.6 min read
#security #ebpf #linux
Open on Medium ↗
Wiki topics: RAG · RAG & Retrieval 🔓 · Open Source 🏃 · Running & Endurance

Your eBPF Security Monitor Is Running. It’s Also Blind.

How writable BPF maps become a telemetry trust boundary weakness in Falco, Tracee, and Tetragon

If you’re running Kubernetes in production, there’s a good chance you’re relying on an eBPF-based security tool — Falco, Tracee, or Tetragon — to watch for container escapes, suspicious process execution, and policy violations. These tools hook deep into the Linux kernel, intercepting syscalls at the tracepoint level before any userspace code can interfere.

Except they can be silently disabled. Without killing the process. Without modifying any files. Without generating a single log entry.

I spent the last few weeks researching how this works, and the results were consistent across all three tools: 100% telemetry suppression, zero indication of tampering.

The Trust Assumption Nobody Questioned

eBPF security tools store their runtime configuration and state in BPF maps — kernel-resident data structures that BPF programs read on every event to decide what to monitor, which processes to track, and how to route events to userspace.

The implicit assumption is straightforward: these maps are only modified by the tool’s own daemon process. Nobody else touches them.

The problem is that the Linux kernel doesn’t enforce this assumption. Any process with CAP_BPF can read, modify, or delete entries in any BPF map on the host. There’s no ownership model. No per-map access control. No audit trail (unless you explicitly configure auditd for bpf() syscalls, which almost nobody does).

And CAP_BPF? It’s privileged, yes — but it’s exactly the kind of capability that becomes available in the scenarios these tools are deployed to detect: container escapes, privilege escalation, misconfigured Kubernetes workloads.

What I Found

I tested three concrete modifications against production releases of each tool:

Tracee v0.24.1: Tracee uses a config_map to store which detection policies are active. A 64-bit field called enabled_policies acts as a bitmask — if a bit is set, that policy’s events are processed. Setting it to zero disables everything. One additional field (policies_version) needs to be bumped to invalidate a per-CPU cache. Two fields modified, total blindness.

Tetragon v1.4.0: Tetragon pins all its BPF maps to well-known filesystem paths under /sys/fs/bpf/tetragon/. The execution monitoring pipeline relies on tail calls through a prog_array called execve_calls. Deleting its two entries causes bpf_tail_call() to silently return — the pipeline breaks. Clearing the process tracking map (execve_map) erases all context.

Falco (latest): Falco’s BPF probes check an array called interesting_syscalls at the very first instruction of every handler. If the entry for a given syscall number is zero, the probe returns immediately. Zeroing all 512 entries makes every probe a no-op.

The Results

Tracee Baseline Events: 16 After Modification: 0 Error Logs: None Health Check: Passes

Tetragon Baseline Events: 14+ After Modification: 0 Error Logs: None Health Check: Passes

Falco Baseline Events: 1+ alerts After Modification: 0 Error Logs: None Health Check: Passes

In every case:

  • The tool’s daemon process keeps running
  • Health endpoints report normal status
  • No kernel log entries are generated
  • The modification takes effect within the next BPF program invocation (essentially instant)
  • The tool recovers fully after restart

This Isn’t a Bug

I want to be clear about framing: this is not a vulnerability in Falco, Tracee, or Tetragon. The bpf() syscall behaves exactly as the kernel designers intended. BPF maps are mutable shared state, accessible to any BPF-capable process.

The issue is architectural. These tools were built on an assumption — that their kernel-side state would remain trustworthy — and the kernel provides no mechanism to enforce that assumption. The tools that exist to detect post-exploitation activity are themselves susceptible to post-exploitation tampering.

It’s the eBPF equivalent of what the Windows security ecosystem has dealt with for years: EDR agents that can be disabled by an attacker operating at the same privilege level. The difference is that EDR vendors have spent a decade building anti-tamper mechanisms. The eBPF ecosystem hasn’t started yet.

What Should Change

The good news is that defense-in-depth measures exist:

For tool maintainers:

  • Use bpf_map_freeze() on maps that don’t change after initialization
  • Implement periodic integrity checks — a userspace thread that reads critical map values every 100ms and alerts or restores on mismatch
  • Add heartbeat canaries: a BPF program writes a rotating value, userspace validates it. If the value stops updating, the pipeline is broken

For operators:

  • Restrict CAP_BPF distribution aggressively — use seccomp to block bpf() for non-monitoring workloads
  • Audit bpf() syscalls via auditd, specifically BPF_MAP_UPDATE_ELEM and BPF_MAP_DELETE_ELEM commands
  • Don’t assume that a running security agent means a working security agent

For kernel developers:

  • Per-map owner binding (restricting map writes to the process that created it) would address the root cause, but doesn’t exist today
  • BPF token scoping (kernel 6.9+) is a step in the right direction but doesn’t provide map-level granularity yet

The Bigger Picture

The cloud-native security stack has a “quis custodiet” problem. We deploy eBPF tools to watch the kernel, but nothing watches the tools. Their runtime state sits in kernel memory, accessible to anything with CAP_BPF, and no one is checking whether that state is still what the tool set it to.

This isn’t theoretical. In a post-exploitation scenario, the attacker’s first action after gaining CAP_BPF can be to disable all monitoring — silently, instantly, with a single command. Everything they do afterward is invisible.

I’m publishing this research to help tool maintainers close the gap. The full technical details, reproducible PoC scripts, and a research tool are available on GitHub:

GitHub: github.com/azqzazq1/SunnyMapBPF

DOI: 10.5281/zenodo.20413161

Azizcan Dastan is a security researcher focused on Linux kernel security, eBPF, and cloud-native attack surfaces.

*GitHub · LinkedIn*


메타데이터
post_id
3de7bc9abc99
slug
your-ebpf-security-monitor-is-running-its-also-blind-3de7bc9abc99
url
https://medium.com/@azizcan.dastan5/your-ebpf-security-monitor-is-running-its-also-blind-3de7bc9abc99
canonical_url
https://medium.com/@azizcan.dastan5/your-ebpf-security-monitor-is-running-its-also-blind-3de7bc9abc99
author_url
https://medium.com/@azizcan.dastan5
status
ok
fetched_at
2026-06-09 15:37:30