eCapture: reading TLS plaintext with eBPF, no CA certificate required
Capturing SSL/TLS plaintext without a CA certificate using eBPF. Supported on Linux/Android kernels for amd64/arm64.
At a glance
- What is it?
- eCapture hooks the TLS libraries a process already links against and copies plaintext out of memory. It works on Linux and Android, needs root or specific capabilities, and is not a packet sniffer in the usual sense.
- Who is it for?
- Adopt eCapture when you control the Linux or Android host, can run as root or with the documented capabilities, and need to see what an unmodified process sends over TLS. Skip it on Windows and macOS, on kernels below 4.18 on x86_64 or 5.5 on aarch64, and whenever a proxy with a trusted CA is acceptable, because that path needs no kernel hooks.
- Can I use it commercially?
- Yes. Apache-2.0 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 4 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The certificate problem eCapture sidesteps
A TLS interception proxy only works because the client trusts the proxy's CA. On a server you own, or on an Android device you are auditing, installing that CA is often the part that is not allowed. A production service may pin certificates, a third-party binary may ship its own trust store, and a mobile app may reject user-installed roots entirely. eCapture takes a different route: it attaches eBPF uprobes to the TLS library functions the process is already calling, so the plaintext exists in memory before it is encrypted and after it is decrypted. Nothing is inserted into the trust chain, and the target program is not modified or restarted.
The audience is narrow and specific. The README requires ROOT permission or specific Linux capabilities, and states that Windows and macOS are not supported. So this is for engineers auditing Linux servers, containers they can run privileged, or Android devices they can root. It is a debugging and audit tool for people who already have host-level access, not a drop-in replacement for a proxy on a workstation.
How the uprobe attach works, and why the kernel version matters
The project is written in C for the eBPF programs and Go for the userspace loader. The repository layout shows kern/ for the eBPF C sources, pkg/ and internal/ for the Go side, and bytecode/ for compiled objects; the Makefile builds those objects and then embeds them as assets. The Go module depends on github.com/cilium/ebpf, github.com/gojue/ebpfmanager, github.com/spf13/cobra and github.com/google/gopacket, which tells you the shape of the thing: eBPF programs loaded through a manager, a cobra subcommand tree, and packet handling for the pcap output path.
For the OpenSSL module, eCapture reads /etc/ld.so.conf to find the shared library search paths and locates the OpenSSL shared object there. It then attaches uprobes to the relevant functions. If the target is statically linked, there is no shared object to find, and the README says you can pass the program path itself as the value of --libssl. That is the mechanism in one sentence: find the library, hook the function, copy the buffer.
The kernel floor is stated per architecture: x86_64 needs 4.18 or newer, aarch64 needs 5.5 or newer, on both Linux and Android. That asymmetry is not cosmetic. aarch64 uprobe and ring buffer support landed later, so an older ARM kernel will refuse the load rather than degrade gracefully. Check uname -r before planning anything.
Installing eCapture and capturing your first HTTPS request
There is no package manager step in the README. You either download the ELF zip from the releases page, unzip it, and run it as root, or you use the Docker image, which the README marks as Linux only.
The Docker path needs the host network and privileged mode, because the tool attaches to host processes and, in pcap mode, to host interfaces:
docker pull gojue/ecapture:latest
docker run --rm --privileged=true --net=host -v ${HOST_PATH}:${CONTAINER_PATH} gojue/ecapture ARGSThe README carries its own warning about --privileged=true granting full host access, and points to docs/minimum-privileges.md for a narrower capability set. Take that seriously on anything shared.
With the binary in place, the first real use is a single subcommand. eCapture detects the system OpenSSL library on its own:
sudo ecapture tlsNow generate traffic from another terminal, for example `curl https://google.com`. The README shows the output as lines tagged with a UUID and a Name field, followed by HTTP/2 header fields such as ":method", ":path" and ":authority". If you see those header lines, the hook is live. If you see nothing, the usual causes are a statically linked client, a TLS stack the module does not cover, or a kernel below the floor.
The OpenSSL module has three output modes. The default text mode prints plaintext. The pcap mode writes a capture file you can open in Wireshark:
sudo ecapture tls -m pcap -i eth0 --pcapfile=ecapture.pcapng tcp port 443And keylog mode writes the TLS master secrets to a file, which you then hand to tshark or Wireshark to decrypt a separate packet capture:
sudo ecapture tls -m keylog -keylogfile=openssl_keylog.logFor live decryption, the README pairs that keylog file with tshark directly:
tshark -o tls.keylog_file:ecapture_masterkey.log -Y http -T fields -e http.file_data -f "port 443" -i eth0Note the default filenames differ between the two commands: --pcapfile defaults to ecapture_openssl.pcapng and --keylogfile defaults to ecapture_masterkey.log. The tshark example uses the default, so if you pass a custom -keylogfile you must pass the same path to tshark.
Eight modules, and the ones that are not about TLS
The README lists 8 modules. Five are TLS-related: tls (OpenSSL, and the README says it supports openssl 1.0.x, 1.1.x and 3.0.x or newer), gnutls, nss for NSS/NSPR, gotls for Go's crypto/tls, and the broader library coverage named in the introduction, which also includes libressl and boringssl. Three are audit modules rather than crypto modules: bash and zsh capture shell commands, and mysqld captures SQL queries from MySQL 5.6, 5.7 and 8.0 and from MariaDB. The module list also includes postgres for SQL queries from PostgreSQL 10 and newer.
The gotls module is the one worth understanding before you assume it works like the others. Because Go programs usually link the TLS implementation into the binary rather than calling a shared library, you point eCapture at the binary itself:
sudo ecapture gotls --elfpath=/home/cfc4n/go_https_client --hexThe README then has you start the program as a separate step. That two-step start is the tell: the hook is attached to an ELF file, and the process has to exist for the uprobe to fire. If you are capturing a long-running daemon, you need to think about whether it is already running when you attach.
The bash and zsh modules are a different product wearing the same binary. Capturing shell commands is host security audit, and the output is whatever anyone types into a shell, which on a shared machine is a lot. The README does not document filtering or redaction for those modules.
Where eCapture is the wrong tool
The first limit is the platform list. Windows and macOS are not supported, full stop. If your audit target is a developer laptop, this is not your tool.
The second is privilege. Root or specific capabilities, by the README's own statement. On managed infrastructure, or in a container platform that forbids privileged containers, that requirement alone ends the conversation. The Docker example uses --privileged=true, and while the project documents a narrower capability set in docs/minimum-privileges.md, the default path in the README is the broad one.
The third is library coverage. eCapture hooks named TLS libraries. A program that uses a TLS implementation outside that set, or that is built with a static, stripped, or otherwise unusual layout, may not be captured by the default detection. The --libssl override exists precisely because detection is not always right.
The fourth is that the README does not document rollback. There is no uninstall or detach procedure described, and no statement about what happens to a hooked process when eCapture exits. That is not the same as saying it is unsafe, but it does mean you should not assume a clean restore path on a production service without testing it yourself on a staging host first.
Finally, this is not a network capture tool in the tcpdump sense. In text mode it reads what the process hands to the TLS library. Traffic that never reaches that library, such as a connection terminated in a kernel TLS path or inside a different runtime, is outside what the module describes.
eCapture against a TLS interception proxy
The obvious alternative is mitmproxy or a similar TLS interception proxy. The difference is architectural, not a matter of features. A proxy is a man in the middle: it terminates the client's TLS session, opens its own session upstream, and re-encrypts. For that to work, the client must trust the proxy CA, and the proxy must be in the network path, which means changing routing or proxy environment variables.
eCapture never terminates a session. It observes the process from inside the kernel, so there is no CA to install, no traffic to reroute, and no change to the application's configuration. That is why it works on binaries that pin certificates or ignore the system trust store, which is exactly where a proxy fails.
The trade runs the other way too. A proxy can modify requests, replay them, and run on a workstation with no kernel requirements. eCapture only observes, needs root, and is tied to a kernel version floor. If you can install a CA and route traffic, a proxy is simpler to operate and far easier to clean up. Reach for eCapture when you cannot do either of those things.
Licence, maintenance and the upgrade bill
The licence is Apache-2.0, which permits commercial use and modification with the usual notice and patent terms. Nothing in the repository suggests a copyleft obligation on the eBPF programs or the Go loader. This is a factual description of the licence identifier, not legal advice; if you plan to redistribute a modified binary, read the LICENSE file and the NOTICE requirements yourself.
On maintenance, the evidence is concrete: the last push to the default branch was on 2026-09-17, and the most recent release is v2.6.0 from 2026-09-09, with v2.5.2 in July 2026 and v2.5.1 in June 2026. The repository is not archived. That is a steady release cadence over the past quarter.
The upgrade cost is real, and it comes from two places. First, the bytecode. The Makefile compiles eBPF C sources into objects and embeds them as assets, so a version upgrade ships new kernel-side programs. Those programs are what the kernel verifies, and a kernel that accepted the previous version is not guaranteed to accept the next one, particularly on older Android kernels near the floor. Second, the Go toolchain: go.mod declares go 1.26.0, so building from source requires a recent Go.
If you consume release binaries rather than building, the upgrade is a file swap. If you build, you inherit a C toolchain, clang and llc, plus the Go version requirement. Budget for testing each upgrade against the specific kernel and TLS library you care about, because that pair is what determines whether the hooks attach.
Editorial conclusion
Adopt eCapture when you control the Linux or Android host, can run as root or with the documented capabilities, and need to see what an unmodified process sends over TLS. Skip it on Windows and macOS, on kernels below 4.18 on x86_64 or 5.5 on aarch64, and whenever a proxy with a trusted CA is acceptable, because that path needs no kernel hooks. Before relying on it, confirm the kernel version on the target, run sudo ecapture tls once against a known HTTPS client, and check whether the target program is statically linked, since the OpenSSL module then needs the program path passed through --libssl.
Frequently asked questions
What is eCapture?
It is a tool that captures SSL/TLS plaintext using eBPF, without a CA certificate. It hooks the TLS library a process already uses, and it supports Linux and Android on x86_64 and aarch64.
Which kernels and platforms does eCapture support?
The README states Linux and Android on x86_64 with kernel 4.18 or newer, and aarch64 with kernel 5.5 or newer. Windows and macOS are not supported.
How do I download and install eCapture?
The README points to the releases page for the ELF zip file, which you unzip and run as root, or to the gojue/ecapture Docker image, which the README marks as Linux only.
Does eCapture need root to run?
The README states it needs ROOT permission or specific Linux capabilities, and links to docs/minimum-privileges.md for the narrower option. The Docker example in the README uses --privileged=true.
What output modes does the eCapture tls module have?
The README describes three: text mode prints plaintext, pcap or pcapng mode writes a capture file for Wireshark, and keylog mode writes TLS master secrets to a file for use with tshark or Wireshark.
Can eCapture capture TLS from a Go program?
Yes, through the gotls module. The README shows running sudo ecapture gotls with --elfpath pointing at the binary, then starting that binary as a separate step.
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/gojue-ecapture)