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 (
--jsor--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 Format
| Response Format | Meaning |
|---|---|
true | Allow the request |
false | Deny the request |
{allow: true} | Allow (object form) |
{allow: false} | Deny (object form) |
| Deny with custom message |
{deny_message: "Blocked"} | Deny (message implies deny) |
| Allow with request body limiting |
Examples:
// 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
// Limit request upload size to 1KB (headers + body)
({allow: {max_tx_bytes: 1024}})
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=debugto 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.
| Response Format | Meaning |
|---|---|
true | Allow the request |
false | Deny the request |
{allow: true} | Allow (object form) |
{allow: false} | Deny (object form) |
| Deny with custom message |
{deny_message: "Blocked"} | Deny (message implies deny) |
| Allow with request body limiting |
Additional:
- Boolean strings:
"true"(allow) or"false"(deny) - same as boolean - 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'}
upload_hosts = {'uploads.example.com'}
for line in sys.stdin:
try:
req = json.loads(line)
if req['host'] in allowed_hosts:
print("true")
elif req['host'] in upload_hosts:
# Limit upload endpoints to 1KB requests
response = {"allow": {"max_tx_bytes": 1024}}
print(json.dumps(response))
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 (
nftcommand) - 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_PROXYandHTTPS_PROXYenvironment 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
--weakto 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.
Request Body Limiting
The max_tx_bytes feature allows you to limit the total size of HTTP requests sent to upstream servers.
This is primarily designed for mitigating code exfiltration attacks through covert channels.
Size Calculation
The max_tx_bytes limit applies to complete HTTP requests, including:
- Request line:
METHOD /path HTTP/1.1\r\n - Headers: Each header as
Name: Value\r\n - Header separator: Final
\r\nbetween headers and body - Body: Request body bytes
Response Format
To enable request body limiting, return an object with max_tx_bytes in your rule response:
// JavaScript engine
{allow: {max_tx_bytes: 1024}} // Limit to 1KB total request size
// Line processor engine
{"allow": {"max_tx_bytes": 1024}}
Note: The
max_tx_bytesfeature is only available in the JavaScript (--js) and Line Processor (--proc) engines, not in Shell scripts.
Behavior
The limiting behavior depends on whether the request includes a Content-Length header:
With Content-Length Header
When the request includes a Content-Length header (most standard HTTP clients):
- Early Detection: httpjail calculates the total request size
- Immediate Rejection: If it exceeds
max_tx_bytes, the client receives a413 Payload Too Largeerror immediately - No Upstream Contact: The upstream server is never contacted, preventing unnecessary load
- Clear Feedback: The error message indicates the actual size and limit
Example error response:
HTTP/1.1 413 Payload Too Large
Content-Type: text/plain
Request body size (5000 bytes) exceeds maximum allowed (1024 bytes)
Without Content-Length Header
When the request uses chunked encoding or doesn't include Content-Length:
- Stream Truncation: The request body is truncated at the limit during streaming
- Upstream Receives Partial: The upstream server receives exactly
max_tx_bytestotal bytes (url + headers + truncated body) - Connection Closes: The connection terminates after reaching the limit
Examples
JavaScript Engine - Upload Endpoint Limiting
// Limit upload endpoints to 1KB total request size
const uploadHosts = ['uploads.example.com', 'upload.github.com'];
uploadHosts.includes(r.host)
? {allow: {max_tx_bytes: 1024}}
: r.host.endsWith('.example.com')
Line Processor Engine - Python Example
#!/usr/bin/env python3
import sys, json
upload_hosts = {'uploads.example.com', 'data.api.com'}
for line in sys.stdin:
try:
req = json.loads(line)
if req['host'] in upload_hosts:
# Limit upload endpoints to 1KB requests
# Returns 413 error if Content-Length exceeds limit
# Truncates body if no Content-Length header
response = {"allow": {"max_tx_bytes": 1024}}
print(json.dumps(response))
elif req['host'].endswith('.example.com'):
print("true")
else:
print("false")
except:
print("false")
sys.stdout.flush()
Use Cases
1. Limiting File Uploads
Prevent users from uploading large files to specific endpoints:
// JavaScript engine
const uploadPaths = ['/upload', '/api/files'];
uploadPaths.some(path => r.path.startsWith(path))
? {allow: {max_tx_bytes: 10485760}} // 10MB limit
: true
2. API Cost Control
Limit request sizes to metered APIs to prevent unexpected costs:
// JavaScript engine
r.host === 'api.expensive-service.com'
? {allow: {max_tx_bytes: 1024}} // 1KB limit for expensive API
: true
3. Data Exfiltration Prevention
Prevent large data uploads that might indicate data exfiltration:
// JavaScript engine
const externalHosts = ['pastebin.com', 'transfer.sh', 'file.io'];
externalHosts.some(host => r.host.includes(host))
? {allow: {max_tx_bytes: 4096}} // 4KB limit for paste sites
: true
Limitations
- Shell scripts: The
max_tx_bytesfeature is not available when using shell script rules (--shell) - HTTP wire format: The byte count is based on HTTP wire format, not just the body size
- Partial uploads: When truncating (no Content-Length), the upstream server receives incomplete data which may cause application errors
See Also
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_PROXYenvironment 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.comenv-var-contents.evil.comapi-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
Where to Report
Most security issues should be reported directly on our issue tracker. Given the early stage of this tool, we encourage clear and public disclosure to help the community stay informed and protected.
Particularly sensitive issues (e.g. those that could lead to arbitrary code execution on the host) should be reported privately to: security@coder.com
Disclosure Preference
Due to the tool's current maturity level, we prefer:
- Early disclosure - Report issues as soon as they're discovered
- Clear communication - Provide detailed reproduction steps and impact assessment
- Public transparency - Use the issue tracker for most reports
As the project matures, we will implement more formal security disclosure processes, including coordinated disclosure timelines and security advisories.
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
- Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
-
Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
-
Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
-
Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.