seccomp-tools, turning a BPF sandbox filter into a policy you can read
Provide powerful tools for seccomp analysis
At a glance
- What is it?
- seccomp-tools is a Ruby command line suite for seccomp filters: it extracts the BPF program from an executable, disassembles it into readable pseudo-instructions, summarises it as a per-action policy, audits it for escape routes, and can assemble or emulate filters of your own. It is aimed at sandbox analysis, and the README says it also works on real-world filters.
- Who is it for?
- seccomp-tools fits a security engineer or a CTF player who needs to know what a sandbox actually permits, because the disassembly, the per-action summary and the audit step each answer a different question about the same filter. It does not fit an engineer who needs proof that a sandbox is correct, since the audit checks known weakness categories rather than the whole space, and it does not work on anything but Linux for the extraction step.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Six subcommands that cover the filter lifecycle
A seccomp filter is a small BPF program that the kernel runs against every syscall a process makes. It is powerful, and it is close to unreadable in its raw form, which is the problem seccomp-tools exists to solve. The suite is built around that lifecycle, and the command list shows it:
seccomp-tools --help
# Usage: seccomp-tools [--version] [--help] <command> [<options>]
# List of commands:
# asm Seccomp bpf assembler.
# audit Assess a seccomp filter for weaknesses and escape routes.
# completion Print a shell completion script.
# disasm Disassemble seccomp bpf.
# dump Automatically dump seccomp bpf from executable(s).
# emu Emulate seccomp rules.
# explain Summarize a seccomp filter as a per-action policy.Dump extracts the filter, disasm renders it, explain turns it into prose, audit looks for ways out of it, asm writes filters, and emu runs them. The ordering is a workflow, and the two ends of it are interesting: asm and emu are for the person writing a filter, while dump, disasm, explain and audit are for the person reading one.
The project's stated audience is primarily, but not exclusively, analysing seccomp sandboxes in capture-the-flag pwn challenges. The README makes the argument that the CTF-specific features are just as useful for analysing real-world seccomp filters, and the audit command in particular is written for production filters rather than for puzzles. Multi-architecture support is listed as a feature, so a filter written for one architecture can be read on another.
dump runs the binary, and that is the price of extraction
The dump command gets the BPF program out of an executable using the ptrace syscall, and the README is direct about the consequence: the target executable is actually run, so you should be careful with untrusted binaries. That warning is the most important line in the documentation, because a tool that analyses sandboxes is exactly the tool you would point at something suspicious.
The options show how much control the command gives you. There is a --sh-exec flag that runs a given command through sh and dumps its seccomp, which is how you pass arguments or pipe things into the target, with the suggestion of using it to keep program output out of the result. It takes precedence over the positional argument. A --limit option dumps only the first LIMIT installed filters, and the default is 1, with the note that an executable is killed once it reaches the limit, so you can cap how many filters you pull out of a program that installs several. A --pid option dumps the filters installed on an existing process, and that one requires CAP_SYS_ADMIN, in practice root. A --timeout bounds the execution, ignored when --pid is given.
The --limit and --timeout combination is what makes the command usable in a pipeline. Without a timeout, a target that waits for input blocks the dump; with one, the command returns what it has. That is a small design decision that shows the author has used this on real binaries rather than only on the ones in the test suite.
Note also that the help text says this command is only available on Linux, which is expected given that it depends on ptrace, and that the rest of the suite is described as multi-architecture.
Three output formats for three different questions
The --format option on dump accepts disasm, raw and inspect, and the three are answers to different questions about the same bytes.
disasm is the default and gives the human-readable view, with syscall names and arguments resolved whenever possible. The output is a table of line, CODE, JT, JF and K, followed by a pseudo-instruction:
seccomp-tools dump spec/binary/twctf-2016-diary
# line CODE JT JF K
# =================================
# 0000: 0x20 0x00 0x00 0x00000000 A = sys_number
# 0001: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0003
# 0002: 0x06 0x00 0x00 0x00000000 return KILL
# 0007: 0x15 0x00 0x01 0x00000038 if (A != clone) goto 0009
# 0017: 0x06 0x00 0x00 0x7fff0000 return ALLOWReading that listing, the filter is a sequence of comparisons against the syscall number, each jumping past a kill, ending in a blanket allow. The names come from the architecture's syscall table, and the disassembly is described as colourful, with simple decompilation on top of the raw instructions.
raw gives you the bytes for re-input, which is what you want when you want to feed a filter back into emu or into a program:
seccomp-tools dump spec/binary/twctf-2016-diary -f raw | xxdinspect gives the same filter as an escaped string literal, in the form a program would use to install it. The three formats together mean you can move from an executable to a readable listing, to bytes, to source, without leaving the tool.
The --output option writes to a file instead of stdout, and it handles the multi-filter case by appending an index, so out.bpf becomes out.bpf, out_1.bpf and so on, which is what you want when a program installs several filters and you want to keep them apart.
explain summarises the policy, audit hunts for the holes
Two commands do the reading that a disassembly cannot do for you.
explain summarises a filter as a per-action policy: which syscalls are allowed, which are killed, and when. The output is the thing a reader actually wants, which is a statement about behaviour rather than a listing of jumps. A filter that kills open, openat, execve, clone, fork, vfork, creat and execveat and allows everything else is one sentence; the same filter as BPF is eighteen instructions of pointer chasing.
audit is the more interesting of the two for production work. It scans a filter for weaknesses and escape routes, and the README names the categories it looks for: missing arch and x32 guards, and dangerous syscalls. The arch and x32 checks are the classic mistakes, because a filter written for one architecture can be reinterpreted on another, and a program that checks the architecture has to check the x32 variant too or it can be run in 32-bit mode around the rules. A tool that points at those two guards by name is doing something a diff of the source would not, because the filter is usually assembled at runtime and never appears in the source at all.
Neither command is a proof. The audit looks for a set of known weakness categories, which is a list rather than a completeness argument, and a filter that passes it can still be wrong. The value is that the list is short enough to check by hand afterwards, and the tool has already done the tedious part of finding the guards that are not there.
asm and emu close the loop on writing filters
The two write-side commands are what make the suite a toolchain rather than a viewer.
asm is described as making writing seccomp rules as easy as writing code. A seccomp filter is normally built by hand-assembling BPF instructions in a C array, with jump offsets computed by the programmer, which is exactly the kind of work that produces off-by-one errors in the branches. Writing the rules in a source form and letting a tool emit the program removes the arithmetic from the task, and it makes the filter reviewable in a diff.
emu emulates seccomp rules, which is the other end of that loop. If you have a filter in a form the assembler accepts, you can run it against candidate syscall sequences and see what the kernel would have done, without writing a program that installs the filter and observing the result. For analysing a filter this is the fastest way to answer a specific question, such as whether a given sequence of calls would be killed, without guessing from the disassembly.
Together with multi-architecture support, this means a filter can be taken apart, understood, modified, re-assembled and tested without leaving the tool, and the examples directory in the repository, with images of a dump and of an emulation run against libseccomp, suggests the author documents the workflow rather than only the commands.
A Ruby gem with a native extension
The distribution channel is RubyGems, and the install is one command:
gem install seccomp-toolsIf the compilation fails, the README suggests installing the build prerequisites and trying again:
sudo apt install gcc ruby-dev makeThe failure mode tells you something about the implementation. A pure-Ruby seccomp tool would have no compilation step, so the fact that a build can fail points at a native extension, and the repository layout supports that reading with an ext/ directory alongside lib/, bin/ and tasks/. The gemspec sits at the root next to the Gemfile, the Gemfile.lock and the Rakefile, and the Rakefile plus the.rspec file and the spec/ directory show an RSpec test suite.
The quality signals are also visible in the badge row: a build status badge, a maintainability badge and a code coverage badge from qlty, and a link to the API documentation on RubyDoc. The.rubocop.yml at the root means the style is enforced by tooling rather than by review comments, and the CHANGELOG.md, README.tpl.md and the tasks/ directory point at a generated README and a task-driven build.
Releases are versioned and reasonably frequent: v1.6.2 on 2025-11-23, v1.7.0 on 2026-08-01 and v1.7.1 on 2026-08-06, with the last push to the repository on 2026-10-17. The licence is MIT, with the text in the LICENSE file at the root, and the completions/ directory holds a shell completion script, which the completion subcommand prints.
Where static filter analysis stops
The first limit is that everything here works on a filter you can get your hands on. dump extracts filters from an executable or from a process, and disasm, explain and audit consume what dump produced. A filter installed by something outside the process, by a kernel module, by a security module or by a container runtime in a way the tool cannot reach, is not in scope, and neither is a filter that is assembled from data at runtime in a form that changes between runs.
The second is platform. The extraction command is documented as Linux only, because it depends on ptrace. Dumping the filters of an existing process needs CAP_SYS_ADMIN, which makes the --pid mode a root operation and therefore something to think twice about before pointing at a process on a shared machine.
The third is the nature of the audit. It checks a set of known weakness categories, missing architecture and x32 guards and dangerous syscalls among them. That is a list, and a list is only as good as its contents. A filter that passes an audit has not been shown to be correct, and the tool's own framing, scanning for weaknesses and escape routes, is careful not to claim more than that.
The fourth is the audience mismatch. The README says the project is aimed primarily, but not exclusively, at capture-the-flag pwn challenges, and that some features are CTF-specific. A production security engineer should therefore expect to read the code as well as use it, and should treat the CTF-derived defaults, such as killing the obvious syscalls, as a starting point rather than a policy. The real-world value of the suite is the same as its CTF value: turning an opaque filter into a statement of what it permits, so that a human can decide whether that is what you meant.
Editorial conclusion
seccomp-tools fits a security engineer or a CTF player who needs to know what a sandbox actually permits, because the disassembly, the per-action summary and the audit step each answer a different question about the same filter. It does not fit an engineer who needs proof that a sandbox is correct, since the audit checks known weakness categories rather than the whole space, and it does not work on anything but Linux for the extraction step. Before using it, read the warning that the target executable is actually run during a dump, so only point it at binaries you trust, and remember that dumping the filters of a running process needs CAP_SYS_ADMIN. The licence is MIT, the gem is seccomp-tools, and v1.7.0 and v1.7.1 were published in August 2026 with the last push on 2026-10-17.
Frequently asked questions
How do I install seccomp-tools?
The gem is published on RubyGems, so `gem install seccomp-tools` is the whole install. If the compilation fails, install the build prerequisites with `sudo apt install gcc ruby-dev make` and run the gem install again.
Is it safe to dump the seccomp filter of an unknown binary?
Not without care. The README notes that the target executable is actually run during a dump, because the BPF is extracted with ptrace, so be careful with untrusted binaries. The --timeout option bounds the execution and the --limit option caps how many installed filters are collected.
What is the difference between seccomp-tools explain and audit?
explain summarises a filter as a per-action policy, naming which syscalls are allowed or killed and when. audit scans a filter for weaknesses and escape routes, with the README naming missing arch and x32 guards and dangerous syscalls as the categories it looks for.
What output formats does seccomp-tools dump support?
Three: disasm, which is the default and gives the readable table of instructions with syscall names resolved; raw, which gives the bytes for re-input; and inspect, which gives the filter as an escaped string literal. The --output option writes to a file, appending an index when several filters are dumped.
Can seccomp-tools dump the filters of a running process?
Yes, with the --pid option, but it requires CAP_SYS_ADMIN, in practice root. The dump command is also Linux only, since it relies on the ptrace syscall, while the rest of the suite supports multiple architectures.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/david942j-seccomp-tools)Was this useful?