BlogDetection

Falco rules that catch real attacks (and skip the noise)

Default rulesets page you for everything. Tune Falco to the syscalls that matter and route the rest to a dashboard.

Nov 25, 2025·13 min readAdvanced

Falco watches the kernel's syscall stream and fires when something matches a rule — a shell in a container, a write under /etc, an outbound connection from a database pod. The problem isn't detection; it's that the default ruleset alerts on so much benign activity that the real signal drowns. A pager that cries wolf gets muted, and a muted detector is no detector at all.

Here's the alert you actually want — an interactive shell opening inside a running container, which is almost never legitimate:

bash — falcolive
falco -r /etc/falco/rules.d/
Falco initialized with 89 rules
watching syscalls via modern eBPF probe ...
 
10:42:01 Warning Shell spawned in a container
(user=root container=api-7f9c shell=bash parent=node)
10:42:07 Notice Package mgmt launched in container (apk add)
 
signal, not noise — nobody should be typing in prod containers
From syscall to pager
1
Syscalls
eBPF probe
2
Rule match
Falco engine
3
Sidekick
fan-out by priority
4
Route
page vs dashboard

A rule that catches what matters

Good rules describe behavior, not strings. 'A shell process, with a TTY, inside a container' is robust — it doesn't care whether the attacker used bash, sh, or busybox. Match on process lineage and container context, and emit fields you'll actually need during triage.

rules.d/shell.yaml
- rule: Terminal shell in container
desc: An interactive shell was opened inside a container
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
output: >
Shell spawned in a container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
priority: WARNING
tags: [container, shell, mitre_execution]

Tune with exceptions, not the mute button

When a rule is noisy, the instinct is to disable it. Don't — that blinds you to the real event. Instead carve a narrow exception for the known-good source, so everything else still fires.

rules.d/shell.yaml
# a debug image your team uses on purpose
- list: allowed_shell_containers
items: ["registry.io/ci-debug", "registry.io/toolbox"]
- rule: Terminal shell in container
append: true
condition: and not container.image.repository in (allowed_shell_containers)
An exception is a decision, log it
Every allowlist entry is a hole you opened on purpose. Keep them in version control with a comment saying who and why, and review them the same way you review firewall rules — otherwise the exception list quietly becomes the attack surface.

Route by priority

Not every alert deserves a 3am page. Send Critical and Warning to the on-call channel, and stream Notice/Informational to a dashboard or your SIEM. Falcosidekick fans a single Falco output stream out to Slack, Loki, and object storage at once.

Where this goes next

Detection is only half the loop — the other half is response. Falco Talon can act on an alert automatically (kill the pod, NetworkPolicy it into isolation) while a human catches up. Start by trusting one high-confidence rule enough to auto-respond; expand from there.

Go deeper in a courseKubernetes security & hardeningRuntime detection, admission control and the full CKS surface.View course

Related posts