httpjail
A cross-platform tool for monitoring and restricting HTTP/HTTPS requests from processes using network isolation and transparent proxy interception.
Warning: httpjail is experimental and offers no API or CLI compatibility guarantees.
What is httpjail?
httpjail provides process-level network isolation and HTTP request control for applications. It acts as a transparent proxy that intercepts all HTTP/HTTPS traffic from a process and its children, allowing you to:
- Monitor all outgoing HTTP/HTTPS requests
- Block requests based on customizable rules
- Log network activity for auditing
- Prevent data exfiltration through DNS
- Isolate processes in restricted network environments
Key Features
- ๐ Process-level network isolation - Isolate processes in restricted network environments
- ๐ HTTP/HTTPS interception - Transparent proxy with TLS certificate injection
- ๐ก๏ธ DNS exfiltration protection - Prevents data leakage through DNS queries
- ๐ง Script-based evaluation - Custom request evaluation logic via external scripts
- ๐ JavaScript evaluation - Fast, secure request filtering using V8 JavaScript engine
- ๐ Request logging - Monitor and log all HTTP/HTTPS requests
- โ Default deny - Requests are blocked unless explicitly allowed
- ๐ฅ๏ธ Cross-platform - Native support for Linux and macOS
- โก Zero configuration - Works out of the box with sensible defaults
Use Cases
- Security auditing - Monitor what network resources an application accesses
- Compliance - Ensure applications only communicate with approved endpoints
- Development - Test applications with restricted network access
- CI/CD - Control and log network access during builds and tests
- Privacy - Prevent applications from phoning home or leaking data
How It Works
httpjail creates an isolated network environment for your process:
- Network Isolation: On Linux, creates a network namespace; on macOS, uses environment variables
- Transparent Proxy: All HTTP/HTTPS traffic is redirected through httpjail's proxy
- Rule Evaluation: Each request is evaluated against your configured rules
- Action: Requests are either allowed through or blocked based on the evaluation
graph LR A[Application] -->|HTTP/HTTPS Request| B[httpjail Proxy] B --> C{Rule Engine} C -->|Allow| D[Forward to Target] C -->|Deny| E[Return 403] D --> F[Target Server] F -->|Response| B B -->|Response| A E -->|Error| A
Getting Started
The simplest way to use httpjail is with JavaScript rules:
# Allow only requests to github.com
httpjail --js "r.host === 'github.com'" -- curl https://github.com
# Block everything (default behavior)
httpjail -- curl https://example.com
For more examples and detailed usage, see the Quick Start guide.
Installation
httpjail can be installed in several ways depending on your needs and platform.
Cargo
If you have Rust installed, you can install httpjail using Cargo:
# optional: brew install rust
cargo install httpjail
This will compile httpjail from source and install it to your Cargo bin directory (usually ~/.cargo/bin/
).
Pre-built Binaries
The easiest way to install httpjail is to download a pre-built binary from the releases page.
Linux
# Download the latest release (example for Linux x86_64)
curl -L https://github.com/coder/httpjail/releases/latest/download/httpjail-linux-amd64 -o httpjail
chmod +x httpjail
sudo mv httpjail /usr/local/bin/
macOS
# Download the latest release (example for macOS arm64)
curl -L https://github.com/coder/httpjail/releases/latest/download/httpjail-darwin-arm64 -o httpjail
chmod +x httpjail
sudo mv httpjail /usr/local/bin/
Build from Source
For development or to get the latest unreleased features:
# Clone the repository
git clone https://github.com/coder/httpjail.git
cd httpjail
# Build in release mode
cargo build --release
# The binary will be at target/release/httpjail
sudo cp target/release/httpjail /usr/local/bin/
Fast Development Builds
For faster builds during development:
cargo build --profile fast
This profile provides reasonable performance with significantly faster build times.
System Requirements
Linux
- Linux kernel 3.8+ (for network namespaces)
- Root privileges (for network namespace creation)
- iptables (for traffic redirection)
macOS
- macOS 10.15+ (Catalina or later)
- No special privileges required (uses weak mode)
Verify Installation
After installation, verify httpjail is working:
# Check version
httpjail --version
# Test with a simple command
httpjail --js "false" -- curl https://example.com
# Should block the request
Trust the CA Certificate (Optional)
For HTTPS interception to work smoothly, you may want to trust httpjail's CA certificate:
# Install the CA certificate to system trust store
httpjail trust --install
# Remove the CA certificate
httpjail trust --uninstall
This is especially important on macOS for applications that use the system keychain (like Go programs).
Next Steps
Now that you have httpjail installed, check out the Quick Start guide to learn how to use it.
Quick Start
This guide will help you get started with httpjail quickly.
Note: By default, httpjail denies all network requests. You must provide rules to allow traffic.
Basic Usage
The basic syntax for httpjail is:
httpjail [OPTIONS] -- <COMMAND> [ARGS...]
Examples
Allow All Requests
# Allow all HTTP/HTTPS requests (not recommended for production)
httpjail --js "true" -- curl https://example.com
Allow Specific Hosts
# Allow only requests to github.com
httpjail --js "r.host === 'github.com'" -- git clone https://github.com/user/repo.git
# Allow multiple hosts
httpjail --js "['github.com', 'api.github.com'].includes(r.host)" -- your-app
# Allow using regex
httpjail --js "/^.*\\.example\\.com$/.test(r.host)" -- npm install
Filter by Method
# Only allow GET requests
httpjail --js "r.method === 'GET'" -- curl https://api.example.com
# Allow GET and POST
httpjail --js "['GET', 'POST'].includes(r.method)" -- your-app
Complex Rules
# Allow only GET requests to api.example.com
httpjail --js "r.host === 'api.example.com' && r.method === 'GET'" -- curl https://api.example.com/data
# Allow specific path patterns
httpjail --js "r.host === 'api.github.com' && r.path.startsWith('/repos/')" -- gh repo list
Using Rule Files
For complex rules, use a JavaScript file:
// rules.js
// Allow GitHub API and npmjs.org
const allowedHosts = [
'api.github.com',
'github.com',
'registry.npmjs.org',
'registry.yarnpkg.com'
];
const isAllowed = allowedHosts.some(host =>
r.host === host || r.host.endsWith('.' + host)
);
// Result (must be a boolean expression)
isAllowed && r.method !== 'DELETE';
httpjail --js-file rules.js -- npm install
Request Logging
Monitor what requests are being made:
# Log to stdout
httpjail --request-log /dev/stdout --js "true" -- your-app
# Log to file
httpjail --request-log requests.log --js "true" -- npm install
# Log format: <timestamp> <+/-> <METHOD> <URL>
# + means allowed, - means blocked
Shell Script Rules
Use a shell script for complex logic:
#!/bin/bash
# check.sh
if [[ "$HTTPJAIL_HOST" == "github.com" ]]; then
exit 0 # Allow
else
echo "Blocked: $HTTPJAIL_HOST is not allowed"
exit 1 # Block
fi
chmod +x check.sh
httpjail --sh ./check.sh -- git clone https://github.com/user/repo.git
Common Patterns
Development Environment
# Allow common development services
httpjail --js "
['localhost', '127.0.0.1', '::1'].includes(r.host) ||
r.host.endsWith('.local') ||
r.host === 'registry.npmjs.org'
" -- npm run dev
CI/CD Pipeline
# Strict rules for CI
httpjail --js-file ci-rules.js --request-log build-requests.log -- make build
Package Installation
# Allow package registries only
httpjail --js "
['registry.npmjs.org', 'registry.yarnpkg.com', 'pypi.org', 'crates.io']
.some(h => r.host === h || r.host.endsWith('.' + h))
" -- npm install
Debugging
When requests are blocked, httpjail returns a 403 Forbidden response with details:
HTTP/1.1 403 Forbidden
Content-Type: text/plain
httpjail: Blocked GET https://blocked.example.com/
Use --request-log
to see all requests and understand what's being blocked:
httpjail --request-log /dev/stderr --js "false" -- curl https://example.com
# Will show: 2024-01-01 12:00:00 - GET https://example.com/
Next Steps
- Learn about JavaScript Rules for more complex filtering
- Explore Configuration options
- Understand Platform Support differences
Configuration
httpjail's behavior can be configured through command-line options, environment variables, and configuration files. This page provides an overview of how these work together.
Configuration Hierarchy
httpjail follows a simple configuration hierarchy:
- Command-line options - Highest priority, override everything
- Environment variables - Set by httpjail for the jailed process
Key Configuration Areas
Rule Engine Selection
Choose how requests are evaluated:
- JavaScript (
--js
or--js-file
) - Fast, sandboxed evaluation - Shell Script (
--sh
) - System integration, external tools - Line Processor (
--proc
) - Stateful, streaming evaluation
Only one rule engine can be active at a time. See Rule Engines for detailed comparison.
Network Mode
Control the isolation level:
- Strong mode (default on Linux) - Full network namespace isolation
- Weak mode (
--weak
) - Environment variables only, no isolation - Server mode (
--server
) - Run as standalone proxy server
Logging and Monitoring
Track what's happening:
- Request logging (
--request-log
) - Log all HTTP requests - Debug output (
RUST_LOG=debug
) - Detailed operational logs - Process output - Captured from the jailed command
See Request Logging for details.
Common Configurations
Development Environment
# Allow localhost and common dev services
httpjail --js "['localhost', '127.0.0.1'].includes(r.host)" \
--request-log /dev/stdout \
-- npm run dev
CI/CD Pipeline
# Strict allow-list for builds
httpjail --js-file ci-rules.js \
--request-log build-network.log \
--timeout 600 \
-- make build
Production Service
# Stateful filtering with monitoring
httpjail --proc ./rate-limiter.py \
--request-log /var/log/httpjail/requests.log \
-- ./api-server
Environment Variables
Set by httpjail
These are automatically set in the jailed process:
Variable | Description | Example |
---|---|---|
HTTP_PROXY | HTTP proxy address | http://127.0.0.1:34567 |
HTTPS_PROXY | HTTPS proxy address | http://127.0.0.1:34567 |
SSL_CERT_FILE | CA certificate path | /tmp/httpjail-ca.pem |
SSL_CERT_DIR | CA certificate directory | /tmp/httpjail-certs/ |
NO_PROXY | Bypass proxy for these hosts | localhost,127.0.0.1 |
Controlling httpjail
These affect httpjail's behavior:
Variable | Description | Example |
---|---|---|
RUST_LOG | Logging level | debug , info , warn , error |
HTTPJAIL_CA_CERT | Custom CA certificate path | /etc/pki/custom-ca.pem |
Platform-Specific Configuration
Linux
- Uses network namespaces for strong isolation
- Requires root/sudo for namespace operations
- iptables rules for traffic redirection
- Supports all network modes
macOS
- Limited to weak mode (environment variables)
- No root required for standard operation
- Certificate trust via Keychain Access
- Some apps may ignore proxy variables
See Platform Support for detailed information.
Troubleshooting Configuration
Rules not matching
# Debug rule evaluation
RUST_LOG=debug httpjail --js "r.host === 'example.com'" -- curl https://example.com
# Log all requests to see what's being evaluated
httpjail --request-log /dev/stderr --js "false" -- your-app
Environment variables not working
# Check what's set in the jail
httpjail --js "true" -- env | grep -E "(HTTP|PROXY|SSL)"
# Verify proxy is listening
httpjail --js "true" -- curl -I http://127.0.0.1:$PROXY_PORT
Certificate issues
# Trust the CA certificate
httpjail trust --install
# Check certificate details
openssl x509 -in ~/.config/httpjail/ca-cert.pem -text -noout
Next Steps
- Rule Engines - Choose the right evaluation method
- Request Logging - Monitor and audit requests
- Platform Support - Platform-specific details
Rule Engines
httpjail provides three different rule engines for evaluating HTTP requests. Each has different trade-offs in terms of performance, flexibility, and ease of use.
Engine Comparison
Feature | JavaScript (V8) | Shell Script | Line Processor |
---|---|---|---|
Performance | |||
Per-Request Latency | 550ยตs-1.3ms | 700ยตs-1.6ms | 70-90ยตs |
Capabilities | |||
Stateful Processing | โ | โ | โ |
External Tool Access | โ | โ | โ |
Language Choice | JS only | Any | Any |
Sandboxed Execution | โ | โ | Depends |
Development Complexity | Easy | Easy | Moderate |
Performance Note: Latency measurements are from benchmarks on modern hardware. JavaScript (V8) creates a new isolate per request for safety. Line processor maintains a persistent process, providing the best performance for high-throughput scenarios.
Examples
Simple Host Filtering
All three engines can handle basic filtering:
JavaScript:
httpjail --js "r.host === 'github.com'" -- command
Shell Script:
#!/bin/bash
[[ "$HTTPJAIL_HOST" == "github.com" ]] && exit 0 || exit 1
Line Processor:
#!/usr/bin/env python3
import sys, json
for line in sys.stdin:
req = json.loads(line)
print("true" if req["host"] == "github.com" else "false")
Complex Logic
For complex scenarios, consider the implementation complexity:
JavaScript - Limited to expression evaluation:
// Complex but still performant
const allowed = ["api.example.com", "cdn.example.com"];
allowed.includes(r.host) && r.method === "GET" && r.path.startsWith("/v1/");
Shell Script - Can use any tool but slower:
#!/bin/bash
# Check against database, but spawns process per request
psql -c "SELECT allowed FROM rules WHERE host='$HTTPJAIL_HOST'" | grep -q true
Line Processor - Best for complex stateful logic:
#!/usr/bin/env python3
# Maintains state, handles thousands of requests efficiently
import sys, json, time
from collections import defaultdict
rate_limits = defaultdict(lambda: {"count": 0, "reset": time.time() + 60})
for line in sys.stdin:
req = json.loads(line)
host_limit = rate_limits[req["host"]]
if time.time() > host_limit["reset"]:
host_limit["count"] = 0
host_limit["reset"] = time.time() + 60
if host_limit["count"] < 100: # 100 requests per minute
host_limit["count"] += 1
print("true")
else:
print("false")
sys.stdout.flush()
Next Steps
- JavaScript Rules - Learn the JavaScript API
- Shell Scripts - Integrate with system tools
- Line Processor - Build stateful filters
JavaScript Rules
Fast, sandboxed request evaluation using the V8 JavaScript engine.
The Request Object
Your JavaScript code receives a r
object with these properties:
r.url
- Full URLr.method
- HTTP method (GET, POST, etc.)r.host
- Hostnamer.scheme
- URL scheme (http/https)r.path
- URL path
Basic Usage
Inline Rules
# Allow specific host
httpjail --js "r.host === 'github.com'" -- command
# Multiple conditions
httpjail --js "r.host === 'api.example.com' && r.method === 'GET'" -- command
# Using arrays
httpjail --js "['GET', 'POST'].includes(r.method)" -- command
File-based Rules
// rules.js
const allowedHosts = ['github.com', 'api.github.com'];
// The last expression is the result
allowedHosts.includes(r.host);
httpjail --js-file rules.js -- command
Response Types
Your JavaScript can return:
- Boolean:
true
to allow,false
to deny - Object with message:
{allow: false, deny_message: "Custom error"}
- Just a message:
{deny_message: "Blocked"}
(implies deny)
// Simple boolean
true // Allow
false // Deny
// With custom deny message (needs parentheses in inline expressions)
({allow: false, deny_message: "Social media blocked"})
// Conditional with message
r.host === 'facebook.com' ? {deny_message: 'Social media blocked'} : true
Common Patterns
Domain Allowlisting
const allowed = ['example.com', 'api.example.com'];
allowed.includes(r.host)
Subdomain Matching
r.host === 'example.com' || r.host.endsWith('.example.com')
Path-based Rules
r.host === 'api.example.com' && r.path.startsWith('/v1/public/')
Method Restrictions
['GET', 'HEAD', 'OPTIONS'].includes(r.method)
Host Whitelist
// Simple host whitelist
const allowedHosts = [
'github.com',
'api.github.com',
'raw.githubusercontent.com',
'codeload.github.com'
];
allowedHosts.includes(r.host)
Host + Method Whitelist
// Allow specific methods only for certain hosts
const rules = [
{host: 'api.github.com', methods: ['GET', 'POST']},
{host: 'github.com', methods: ['GET']},
{host: 'uploads.github.com', methods: ['POST', 'PUT']}
];
rules.some(rule =>
rule.host === r.host && rule.methods.includes(r.method)
)
Regexp Matching on Method + URL
// Whitelist patterns for METHOD + URL combinations
const patterns = [
/^GET api\.github\.com\/repos\/.+/,
/^POST api\.example\.com\/v[12]\/.*/,
/^(GET|HEAD) .*\.cdn\.example\.com\/.*\.(jpg|png|gif)/
];
// Build request string using host and path for simpler patterns
const requestString = `${r.method} ${r.host}${r.path}`;
patterns.some(pattern => pattern.test(requestString))
When to Use
Best for:
- Simple host/path filtering
- Quick prototyping
- Untrusted rule sources (sandboxed)
Avoid for:
- Stateful processing (use line processor)
- External integrations (use shell or line processor)
Shell Script Rule Engine
Execute external scripts or programs to evaluate HTTP requests. Use any language or integrate with external systems.
How It Works
With --sh
, httpjail executes your script for each request, passing details through environment variables. Exit code 0 allows the request, non-zero denies it.
Basic Usage
# Use a shell script for evaluation
httpjail --sh "./policy.sh" -- curl https://api.example.com
# Use an inline command
httpjail --sh "exit 0" -- curl https://example.com # Allow all
# Use any executable
httpjail --sh "/usr/local/bin/my-policy-checker" -- ./my-app
Environment Variables
Your script receives the following environment variables:
Variable | Description | Example |
---|---|---|
HTTPJAIL_URL | Complete request URL | https://api.github.com/repos |
HTTPJAIL_METHOD | HTTP method | GET , POST , PUT , etc. |
HTTPJAIL_SCHEME | URL scheme | http or https |
HTTPJAIL_HOST | Hostname from URL | api.github.com |
HTTPJAIL_PATH | URL path | /repos |
HTTPJAIL_REQUESTER_IP | IP of the requesting process | 127.0.0.1 |
Exit Codes and Output
- Exit code 0: Request is allowed
- Any non-zero exit code: Request is denied
- stdout: Becomes the response body for denied requests (useful for custom error messages)
- stderr: Logged for debugging (use
RUST_LOG=debug
to see)
Examples
Simple Allow/Deny Script
#!/bin/sh
# allow-github.sh - Only allow GitHub API requests
case "$HTTPJAIL_HOST" in
api.github.com|github.com)
exit 0 # Allow
;;
*)
echo "Only GitHub requests allowed"
exit 1 # Deny
;;
esac
Domain Allowlist
Command:
httpjail --sh "./rules.sh" -- curl https://api.github.com/repos
In whitelist.txt
:
api.github.com
github.com
raw.githubusercontent.com
api.gitlab.com
gitlab.com
In rules.sh
:
#!/bin/sh
# Check if host is in whitelist file
# Read whitelist file (one domain per line)
WHITELIST_FILE="./whitelist.txt"
# Check if whitelist file exists
if [ ! -f "$WHITELIST_FILE" ]; then
echo "Whitelist file not found: $WHITELIST_FILE"
exit 1
fi
# Check if current host is in the whitelist (exact match)
if grep -Fxq "$HTTPJAIL_HOST" "$WHITELIST_FILE"; then
exit 0 # Allow
else
echo "Host $HTTPJAIL_HOST not in whitelist"
exit 1 # Deny
fi
Method-Based Restrictions
#!/bin/sh
# read-only.sh - Only allow safe HTTP methods
case "$HTTPJAIL_METHOD" in
GET|HEAD|OPTIONS)
exit 0
;;
*)
echo "Method $HTTPJAIL_METHOD not allowed (read-only mode)"
exit 1
;;
esac
Using Other Languages
#!/usr/bin/env python3
import os, sys
if os.environ.get('HTTPJAIL_HOST') == 'api.github.com':
sys.exit(0) # Allow
else:
print("Only GitHub API allowed")
sys.exit(1) # Deny
Script vs Command
httpjail determines how to execute your script:
- Contains spaces: Executed as
sh -c "your command"
- No spaces: Executed directly as a binary/script
# These are equivalent:
httpjail --sh "exit 0" -- curl example.com
httpjail --sh "./my-script.sh" -- curl example.com
# But this runs the binary directly (more efficient):
httpjail --sh "/usr/local/bin/policy-check" -- curl example.com
Error Handling
Script Not Found
$ httpjail --sh "./nonexistent.sh" -- curl example.com
# Error: Script execution failed: No such file or directory
Script Not Executable
$ httpjail --sh "./policy.sh" -- curl example.com
# Error: Script execution failed: Permission denied
# Fix: chmod +x ./policy.sh
Script Timeout
Scripts that run longer than 30 seconds are automatically terminated:
#!/bin/sh
# This will timeout
sleep 60
exit 0
When to Use Shell Scripts
Best for:
- External integrations (databases, APIs)
- Reusing existing scripts/tools
- Any programming language
Avoid for:
- High-throughput scenarios (use line processor mode)
- Simple logic (use JavaScript)
For high-throughput scenarios, consider the Line Processor mode which maintains a single process.
Line Processor
Stream requests to a long-running process for stateful, high-performance filtering.
How It Works
- httpjail spawns your processor once at startup
- For each HTTP request, httpjail sends a JSON line to the processor's stdin
- The processor evaluates and responds with "true" or "false"
- The process continues running until httpjail exits
Protocol
Request Format
Each request is sent as a single JSON line:
{
"url": "https://example.com/api",
"method": "GET",
"host": "example.com",
"scheme": "https",
"path": "/api"
}
Response Format
Your processor must respond with one line per request:
- Boolean strings:
"true"
(allow) or"false"
(deny) - JSON object:
{"allow": false, "deny_message": "Blocked by policy"}
- JSON with message only:
{"deny_message": "Blocked"}
(implies deny) - Any other text: Treated as deny with that text as the message (e.g.,
"Access denied"
becomes a deny with message "Access denied")
Command Line Usage
# Use a Python script as processor
httpjail --proc ./filter.py -- your-command
# Use any executable
httpjail --proc "/usr/bin/python3 -u filter.py" -- your-command
# Pass arguments to the processor
httpjail --proc "./filter.sh --strict" -- your-command
Examples
Python Example
#!/usr/bin/env python3
import sys, json
allowed_hosts = {'github.com', 'api.github.com'}
for line in sys.stdin:
try:
req = json.loads(line)
if req['host'] in allowed_hosts:
print("true")
else:
# Can return JSON for custom messages
response = {"allow": False, "deny_message": f"{req['host']} not allowed"}
print(json.dumps(response))
except:
print("Invalid request") # Any non-boolean text becomes deny message
sys.stdout.flush() # Ensure immediate response
Bash Example
#!/bin/bash
while IFS= read -r line; do
host=$(echo "$line" | jq -r .host)
if [[ "$host" == *.github.com ]]; then
echo "true"
else
echo "false"
fi
done
Important Notes
- Flush output after each response (
sys.stdout.flush()
in Python, automatic in bash) - Handle errors gracefully - always respond with allow or deny
- Use stderr for debugging - stdout is reserved for responses
Best for
- High-throughput scenarios
- Stateful processing (caching, rate limiting)
- Complex logic requiring external libraries
Platform Support
httpjail works differently on each platform due to OS-specific networking capabilities.
Platform Comparison
Feature | Linux | macOS | Windows |
---|---|---|---|
Traffic isolation | โ Namespaces + nftables | โ ๏ธ Env vars only | ๐ง Planned |
TLS interception | โ Transparent | โ Via proxy settings | ๐ง Planned |
Sudo required | โ ๏ธ Yes | โ No | ๐ง |
Force all traffic | โ Yes | โ Apps must cooperate | ๐ง |
Linux
Full network isolation using namespaces and nftables.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ httpjail Process โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. Create network namespace โ
โ 2. Setup nftables rules โ
โ 3. Start embedded proxy + DNS server โ
โ 4. Export CA trust env vars โ
โ 5. Execute target process in namespace โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Target Process โ
โ โข Isolated in network namespace โ
โ โข User dropped to $SUDO_USER โ
โ โข All HTTP/HTTPS โ local proxy โ
โ โข All DNS queries โ dummy resolver (6.6.6.6) โ
โ โข CA cert trusted via env vars โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Prerequisites
- Linux kernel 3.8+ (network namespace support)
- nftables (
nft
command) - libssl-dev (for TLS)
- sudo access (for namespace creation)
How It Works
- Creates isolated network namespace
- Uses nftables to redirect all HTTP/HTTPS traffic
- Intercepts DNS queries (returns 6.6.6.6 to prevent exfiltration)
- Transparent TLS interception with per-host certificates
Usage
# Strong mode (default) - full isolation
sudo httpjail --js "r.host === 'github.com'" -- curl https://api.github.com
# Weak mode - environment variables only (no sudo)
httpjail --weak --js "r.host === 'github.com'" -- curl https://api.github.com
macOS
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ httpjail Process โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 1. Start HTTP/HTTPS proxy servers โ
โ 2. Set HTTP_PROXY/HTTPS_PROXY env vars โ
โ 3. Generate/load CA certificate โ
โ 4. Execute target with proxy environment โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Target Process โ
โ โข HTTP_PROXY/HTTPS_PROXY environment vars โ
โ โข Applications must respect proxy settings โ
โ โข CA cert via environment variables โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Note: Due to macOS PF (Packet Filter) limitations, httpjail uses environment-based proxy configuration on macOS. PF translation rules (such as rdr
and route-to
) cannot match on user or group, making transparent traffic interception impossible. As a result, httpjail operates in "weak mode" on macOS, relying on applications to respect the HTTP_PROXY
and HTTPS_PROXY
environment variables. Most command-line tools and modern applications respect these settings, but some may bypass them. See also https://github.com/coder/httpjail/issues/7.
Prerequisites
- No special permissions required
- Applications must respect proxy environment variables
Certificate Trust
httpjail generates a unique CA certificate for TLS interception:
# Check if CA is trusted
httpjail trust
# Install CA to user keychain (prompts for password)
httpjail trust --install
# Remove CA from keychain
httpjail trust --remove
Note: Most CLI tools respect the SSL_CERT_FILE
environment variable that httpjail sets automatically. Go programs require the CA in the keychain.
How It Works
- Sets
HTTP_PROXY
andHTTPS_PROXY
environment variables - Applications must voluntarily use these proxy settings
- Cannot force traffic from non-cooperating applications
- DNS queries are not intercepted
Usage
# Always runs in weak mode on macOS (no sudo needed)
httpjail --js "r.host === 'github.com'" -- curl https://api.github.com
Windows
Support is planned but not yet implemented.
Mode Selection
httpjail automatically selects the appropriate mode:
- Linux: Strong mode by default, use
--weak
to force environment-only mode - macOS: Always weak mode (environment variables)
- Windows: Not yet supported
Environment Variables
httpjail sets these variables for the child process to trust the CA certificate:
SSL_CERT_FILE
/SSL_CERT_DIR
- OpenSSL and most toolsCURL_CA_BUNDLE
- curlREQUESTS_CA_BUNDLE
- Python requestsNODE_EXTRA_CA_CERTS
- Node.jsCARGO_HTTP_CAINFO
- CargoGIT_SSL_CAINFO
- Git
Request Logging
Log all HTTP/HTTPS requests to a file for auditing, debugging, or analysis.
Basic Usage
httpjail --request-log requests.log --js "true" -- npm install
Log Format
Each request is logged on a single line:
<timestamp> <+/-> <METHOD> <URL>
+
indicates allowed requests-
indicates blocked requests
Example Output
2025-09-22T14:23:45.123Z + GET https://registry.npmjs.org/react
2025-09-22T14:23:45.234Z + GET https://registry.npmjs.org/react-dom
2025-09-22T14:23:45.345Z - POST https://analytics.example.com/track
Example: BigQuery Integration
Achieve more advanced logging with the line processor
rule engine (--proc
). Here's an example of how to log to
every request to BigQuery:
#!/bin/bash
# log-to-bigquery.sh
while read -r line; do
# Create BigQuery insert payload
echo "$line" | jq -c '{
rows: [{
insertId: (now | tostring),
json: . + {timestamp: (now | todate)}
}]
}' | bq insert my-project:httpjail_logs.requests
# Allow all requests
echo "true"
done
Usage:
httpjail --proc ./log-to-bigquery.sh --request-log local-backup.log -- your-app
This example shows real-time logging where each request is immediately inserted into BigQuery. Note: bq insert
is intended for testing only - for production use BigQuery client libraries.
TLS Interception
httpjail intercepts HTTPS traffic using a locally-generated Certificate Authority (CA) to inspect and filter encrypted requests.
How It Works
- CA Generation: On first run, httpjail creates a unique CA keypair
- Certificate Storage: CA files are stored in your config directory:
- Linux:
~/.config/httpjail/
- macOS:
~/Library/Application Support/httpjail/
- Windows:
%APPDATA%\httpjail\
(planned)
- Linux:
- Process Trust: The jailed process trusts the CA via environment variables
- Per-Host Certificates: Each HTTPS connection gets a certificate signed by the httpjail CA
- No System Changes: Your system trust store is never modified
Certificate Trust
httpjail sets these environment variables for the child process:
SSL_CERT_FILE
/SSL_CERT_DIR
- OpenSSL and most toolsCURL_CA_BUNDLE
- curlREQUESTS_CA_BUNDLE
- Python requestsNODE_EXTRA_CA_CERTS
- Node.jsCARGO_HTTP_CAINFO
- CargoGIT_SSL_CAINFO
- Git
Platform Differences
Linux (Strong Mode)
- Transparently redirects TCP port 443 to the proxy
- Extracts SNI from TLS ClientHello
- No application cooperation needed
macOS (Weak Mode)
- Uses
HTTP_PROXY
/HTTPS_PROXY
environment variables - HTTPS negotiated via CONNECT method
- Applications must respect proxy settings
Application Support
Platform | Environment Variables | System Trust Store |
---|---|---|
Linux | ๐ข Vast majority | N/A |
macOS | ๐ Some | ๐ข Vast majority |
Most CLI tools and libraries respect the CA environment variables that httpjail sets. On macOS, some tools (e.g. those built with Go) ignore these variables and require system trust. As Linux doesn't have a concept of a "system trust store" the environment variables are well supported.
On macOS, you can install the CA certificate to the keychain using httpjail trust --install
.
DNS Exfiltration
httpjail prevents DNS exfiltration attacks by intercepting all DNS queries in isolated environments.
The Attack
Malicious code can exfiltrate sensitive data by encoding it in DNS queries:
secret-data.attacker.com
env-var-contents.evil.com
api-key-12345.tunnel.io
These queries reach public DNS servers even when HTTP/HTTPS traffic is blocked.
How Protection Works
In Linux strong mode, httpjail:
- Intercepts all DNS queries from the jailed process
- Returns dummy response (6.6.6.6) for every query
- Prevents external DNS access - queries never reach public resolvers
- Maintains HTTP/HTTPS functionality through transparent proxy redirection
Traffic Flow
sequenceDiagram participant J as Jailed Process participant S as Jail Server participant D as Public DNS Resolvers Note over J,D: DNS Exfiltration Attempt J->>S: DNS Query: secret-data.attacker.com S-->>J: Response: 6.6.6.6 (dummy) Note over S,D: โ Query never reaches public resolvers Note over J,D: Blocked HTTP Flow J->>S: HTTP GET http://blocked.com Note over S: Rule evaluation: denied S-->>J: 403 Forbidden Note over S,D: โ No DNS resolution needed Note over J,D: Allowed HTTP Flow J->>S: HTTP GET http://example.com Note over S: Rule evaluation: allowed S->>D: DNS Query: example.com (only if needed) D-->>S: Real IP address S->>S: Forward to upstream server S-->>J: HTTP response
The diagram shows three scenarios:
- DNS Exfiltration Prevention: All DNS queries receive dummy response, never reaching public resolvers
- Blocked HTTP Traffic: Requests denied by rules without any DNS resolution
- Allowed HTTP Traffic: Only when rules permit, httpjail performs actual DNS resolution
Platform Support
- Linux (Strong Mode): Full DNS interception and protection
- macOS (Weak Mode): No DNS interception - applications resolve normally
- Windows: Planned
Why 6.6.6.6?
The choice of 6.6.6.6 is arbitrary - any non-lookback IP would work.
Server Mode
Run httpjail as a standalone proxy server without executing any commands. Useful for proxying multiple applications through the same httpjail instance.
The server binds to localhost (127.0.0.1) by default for security.
# Start server with default ports (8080 for HTTP, 8443 for HTTPS) on localhost
httpjail --server --js "true"
# Start server with custom ports using environment variables
HTTPJAIL_HTTP_BIND=3128 HTTPJAIL_HTTPS_BIND=3129 httpjail --server --js "true"
# Bind to all interfaces (use with caution - exposes proxy to network)
HTTPJAIL_HTTP_BIND=0.0.0.0:8080 HTTPJAIL_HTTPS_BIND=0.0.0.0:8443 httpjail --server --js "true"
# Configure your applications to use the proxy:
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8443
curl https://github.com # This request will go through httpjail
Note: In server mode, httpjail does not create network isolation. Applications must be configured to use the proxy via environment variables or application-specific proxy settings.
Server Mode is particularly powerful when paired with network-level firewall rules that force HTTP(s) traffic through the proxy.
Security Policy
MIT License
Copyright (c) 2018 Michael Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.