Executive Summary
PhantomAPI is a zero-touch API structural drift detector that operates at the Linux kernel level using eBPF (extended Berkeley Packet Filter). It attaches to running processes by PID, observes HTTP and HTTPS response structure in real time, and alerts when API response fields disappear, change type, or appear unexpectedly.
This document addresses the security implications of deploying PhantomAPI in production infrastructure.
PhantomAPI reads API response structure but never stores, transmits, or logs response content. Only structural metadata — field names, types, and drift classifications — ever leaves the observed machine.
How PhantomAPI Works
The eBPF Foundation
eBPF is a technology built into the Linux kernel (version 4.x and later) that allows small, verified programs to run inside the kernel without modifying kernel source code or loading traditional kernel modules. eBPF is used in production at companies including Meta, Google, Netflix, and Cloudflare for observability, networking, and security.
PhantomAPI uses eBPF to observe system calls — specifically, the read, write, sendto, and recvfrom calls that applications use to send and receive network data. By attaching to these syscall tracepoints, PhantomAPI can see the raw bytes flowing through a process's network connections without injecting a proxy, modifying application code, or intercepting traffic on the network.
TLS/HTTPS Visibility
For encrypted HTTPS traffic, PhantomAPI attaches eBPF uprobes to the SSL_read and SSL_write functions in the target process. When the process dynamically links libssl, the uprobes attach to the shared library. When OpenSSL is statically linked into the binary itself — as in Node.js v20 and later, and many Go binaries — the uprobes attach directly to the target's own executable via /proc/<pid>/exe. In both cases the uprobes fire after TLS decryption has already occurred inside the application's own process, allowing PhantomAPI to observe the plaintext HTTP data in memory. This is the same approach used by established open-source security and observability tools.
PhantomAPI does not perform TLS interception. It does not terminate, proxy, or man-in-the-middle any connections. Instead, it attaches to the application's own TLS library via eBPF uprobes that fire after decryption has already occurred inside the application's process. PhantomAPI reads the plaintext data in the application's own memory space — it never handles, negotiates, or interferes with the TLS session itself.
The Detection Pipeline
Once PhantomAPI captures HTTP response data from the kernel, the data flows through a user-space pipeline written in Go:
- Reconstruction: Raw syscall data fragments are reassembled into complete HTTP response pairs.
- Fingerprinting: The JSON response body is walked to extract structural metadata — field names, nesting paths, data types, and null frequency. No field values are recorded.
- Drift Detection: The current structural fingerprint is compared against a baseline. If a field has disappeared, changed type, or appeared unexpectedly, a drift finding is generated.
- Reporting: Drift findings are sent as lightweight JSON metadata to the PhantomAPI cloud backend for storage and alerting.
The response body is held in memory only long enough to extract field structure. It is never written to disk, never logged, and never transmitted.
What Data Leaves the Machine
When PhantomAPI detects a drift event, it sends a small JSON payload to the configured backend endpoint. Here is the exact structure of that payload:
{
"endpoint": "/api/orders",
"method": "GET",
"field_name": "data.shipping.carrier",
"kind": "new_field",
"risk": "Medium",
"detail": "not present in baseline"
}That is the complete outbound payload. It contains:
- The API endpoint path and HTTP method
- The dotted field path that drifted (e.g.,
data.shipping.carrier) - The type of drift (new field, missing field, type change, or null frequency shift)
- A risk classification (High, Medium, or Low)
- A human-readable description of the change
It does not contain:
- Request or response bodies
- Field values, user data, or PII
- Authentication tokens, cookies, or headers
- IP addresses of downstream clients
- Raw network traffic of any kind
Kernel Safety Guarantees
The eBPF Verifier
Every eBPF program must pass through the Linux kernel's built-in verifier before it is allowed to execute. The verifier is a static analysis engine that enforces hard safety constraints:
- No unbounded loops — every loop must have a provable upper bound
- No out-of-bounds memory access — all pointer arithmetic is checked
- No arbitrary code execution — only a restricted set of eBPF helper functions are available
- No writes to process memory — eBPF programs attached to tracepoints are strictly read-only observers
- Stack size limited to 512 bytes — prevents stack overflow by design
- Maximum instruction count enforced — programs that are too complex are rejected at load time
If an eBPF program fails verification, the kernel refuses to load it. There is no override. This is a hard guarantee enforced by the kernel itself, not by PhantomAPI.
Process Isolation
PhantomAPI runs as a separate user-space process. It does not inject code into, attach a debugger to, or modify the memory of the observed application. The eBPF programs run in kernel space and emit data to a perf event buffer, which the PhantomAPI Go process reads from user space.
If PhantomAPI crashes, the observed application is completely unaffected. The eBPF programs are automatically cleaned up by the kernel when the loading process exits. There is no residual kernel state, no orphaned hooks, and no performance impact on the observed process after PhantomAPI stops.
Performance Impact
eBPF tracepoint and uprobe programs add microsecond-level overhead to the hooked system calls. In practice, this overhead is negligible for API servers handling typical request volumes. PhantomAPI uses per-CPU scratch buffers to avoid lock contention and does not allocate kernel memory beyond its initial map setup.
Privilege Requirements
PhantomAPI requires elevated privileges to load eBPF programs into the kernel. There are two options:
Option A — Root access: Running with sudo or as root. This is the simplest deployment path and is appropriate for dedicated monitoring hosts or containers with controlled access.
Option B — Linux capabilities: Granting CAP_BPF and CAP_PERFMON to the binary. CAP_BPF allows loading and managing eBPF programs. CAP_PERFMON allows attaching to performance monitoring events (which includes tracepoints and uprobes). These capabilities are narrowly scoped — they do not grant general root access, file system access, or network administration privileges.
In containerized environments, these capabilities can be granted at the container level without giving the container full root access to the host.
Network Security
PhantomAPI makes exactly one type of outbound network call: an HTTP POST to the configured backend URL, carrying the drift event metadata described in Section 3.
The binary authenticates to the PhantomAPI backend using a license key passed via the --license-key flag at startup. This key is included as an x-api-key header on every outbound request. License keys are scoped per user and validated server-side before any data is written. PhantomAPI does not contact any hardcoded external servers, does not phone home, and does not transmit telemetry.
Outbound network behavior depends on the command and configuration:
inspect/watch: no outbound connection is made unless both a license key and a cloud URL are configured. Without them, drift detection runs fully locally and no data leaves the machine.- Built-in packs (Stripe, Google Maps, OpenAI, Anthropic, Gemini): ship with the binary and require no network access.
- Custom packs fetched by name from the cloud are retrieved over HTTPS from the configured cloud URL.
pack-build: uploads the captured baseline to the cloud URL over HTTPS; this is the only command that transmits fingerprint data by design.
For PhantomAPI Cloud customers, drift events are sent to your dedicated backend endpoint over HTTPS. All communication between the binary and the backend is authenticated — unauthenticated requests are rejected before reaching the database.
Binary Verification
PhantomAPI distributes pre-compiled Linux amd64 binaries via GitHub Releases on a private repository. Each release includes:
- The compiled binary (
phantomapi-linux-amd64) - A SHA-256 checksum file for verification
- Release notes describing changes since the previous version
To verify a downloaded binary:
sha256sum phantomapi-linux-amd64Compare the output against the published checksum in the release. If they do not match, do not run the binary.
The PhantomAPI install script (available at phantomapi.dev/install.sh) automates download and checksum verification in a single step.
Inspecting the Loaded eBPF Programs
Beyond verifying the binary you downloaded, you can verify what PhantomAPI actually loads into your kernel at runtime. While PhantomAPI is running, use bpftool (shipped with the Linux kernel source) to list the loaded programs and dump their verifier-translated bytecode:
sudo bpftool prog show
sudo bpftool prog dump xlated id <PROG_ID>
sudo bpftool map showThe first command lists every eBPF program attached on the host, including those loaded by PhantomAPI. The second prints the bytecode the kernel verifier actually accepted, which is what runs — not just what was submitted. The third lists the eBPF maps in use. This lets security teams independently confirm that PhantomAPI only attaches the syscall tracepoints and TLS uprobes described in Section 2, without relying on any claim we make about our source code.
Data Handling Summary
| Data Type | Stored Locally | Transmitted |
|---|---|---|
| HTTP/HTTPS response bodies | No (in-memory only) | Never |
| Request bodies | No | Never |
| Field values / PII | No | Never |
| Auth tokens / cookies / headers | No | Never |
| Field names and types (structure) | In-memory during analysis | Never |
| Drift event metadata | No | Yes (see Section 3) |
| Endpoint paths and methods | No | Yes (in drift events) |
| Risk classifications | No | Yes (in drift events) |
Cloud Data Retention
When PhantomAPI Cloud receives drift event metadata, that data is stored in a managed PostgreSQL database with encryption at rest enabled. Data is retained according to the customer's subscription tier:
- Free: no cloud history — drift detection is real-time and ephemeral; no drift events are stored server-side
- PhantomWatch: 90-day rolling history window
Drift events older than the retention window are automatically deleted. Customers can request immediate deletion of all stored data at any time by contacting kevin@phantomapi.dev. As a reminder, the only data stored is the structural metadata described in Section 3 — no request bodies, response content, or PII is ever persisted.
Backend Security Controls
The PhantomAPI Cloud backend enforces the following security controls:
- Encryption in transit: All communication between the PhantomAPI binary and the cloud backend occurs over TLS 1.2 or higher. The dashboard is served over HTTPS.
- Encryption at rest: The PostgreSQL database that stores drift event metadata is encrypted at rest using AES-256, managed by the hosting provider.
- API key authentication: Every inbound request from the PhantomAPI binary is authenticated using an API key validated server-side. Unauthenticated requests are rejected before reaching the database.
- Tenant isolation: Every authenticated request is scoped to a single user ID, resolved from the license key on each inbound call. Backend queries explicitly filter by that user ID before reading or writing drift events, endpoints, or webhook configurations. License keys are never shared across user accounts and are re-validated against the database on every request before any other operation proceeds.
- Dashboard authentication: The PhantomAPI dashboard requires email and password authentication. Sessions are managed with secure token handling. Password reset flows are available and use authenticated email delivery.
Threat Model
PhantomAPI is designed to detect one specific class of problem: silent structural changes in third-party APIs that your application depends on. It is important to be clear about what PhantomAPI does and does not detect.
PhantomAPI detects:
- Fields disappearing from API responses (
missing_field) - Fields changing data type (
type_change) - New unexpected fields appearing in responses (
new_field) - Shifts in null frequency for existing fields (
null_freq_shift)
PhantomAPI does not detect:
- Malicious payloads or injection attacks
- Authentication or authorization vulnerabilities in observed APIs
- Data exfiltration or data leakage
- Changes in response values (only structural changes are tracked)
- Network-level threats such as DNS hijacking or BGP manipulation
PhantomAPI is not a security scanner, WAF, or vulnerability assessment tool. It is a reliability tool that detects when the third-party APIs your application depends on silently change their response structure in ways that could break your integration.
Assumptions and Known Limits
PhantomAPI's safety properties depend on two assumptions that are worth making explicit:
- The observed process is not already compromised. PhantomAPI reads plaintext HTTP data after the application's own TLS library has decrypted it, inside the application's own memory. If an attacker has already achieved code execution in the target process, they can influence what PhantomAPI observes — PhantomAPI is an integrity check against silent API drift, not against an adversary running inside your own service.
- The host kernel is reasonably current. eBPF's safety rests on the in-kernel verifier, which has had verifier-escape vulnerabilities disclosed and patched over the years. Customers running PhantomAPI should keep their kernel patched on whatever cadence their operations team uses for other kernel-level security fixes. Older, unpatched kernels expose more than PhantomAPI's own surface — they expose the entire eBPF subsystem.
Neither of these is unique to PhantomAPI; any eBPF-based tool inherits the same dependencies. They're called out here so they're not implicit.
Frequently Asked Questions
SSL_read and SSL_write and see only the buffer pointer those functions receive plus the returned length — the TLS plaintext that's already in the application's hands. eBPF as a technology has the capability to read arbitrary user memory via bpf_probe_read_user, but PhantomAPI's program only reads within that TLS buffer range. This is verifiable independently by dumping the loaded program with sudo bpftool prog dump xlated (see Section 7). Environment variables, heap secrets, and everything else in the process's address space are out of scope.SSL_read and SSL_write. Services using non-OpenSSL TLS stacks — pure Go (crypto/tls), Rust with rustls, BoringSSL, and similar — will not have their encrypted traffic decoded; PhantomAPI will only observe cleartext HTTP on those processes. Most Node.js, Python, and Ruby runtimes ship with OpenSSL and work out of the box. Go services that link OpenSSL through cgo also work; Go services using the standard library's TLS do not.