Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

httpjail

Crates.io CI

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:

  1. Network Isolation: On Linux, creates a network namespace; on macOS, uses environment variables
  2. Transparent Proxy: All HTTP/HTTPS traffic is redirected through httpjail's proxy
  3. Rule Evaluation: Each request is evaluated against your configured rules
  4. 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

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:

  1. Command-line options - Highest priority, override everything
  2. 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:

VariableDescriptionExample
HTTP_PROXYHTTP proxy addresshttp://127.0.0.1:34567
HTTPS_PROXYHTTPS proxy addresshttp://127.0.0.1:34567
SSL_CERT_FILECA certificate path/tmp/httpjail-ca.pem
SSL_CERT_DIRCA certificate directory/tmp/httpjail-certs/
NO_PROXYBypass proxy for these hostslocalhost,127.0.0.1

Controlling httpjail

These affect httpjail's behavior:

VariableDescriptionExample
RUST_LOGLogging leveldebug, info, warn, error
HTTPJAIL_CA_CERTCustom 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

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

FeatureJavaScript (V8)Shell ScriptLine Processor
Performance
Per-Request Latency550ยตs-1.3ms700ยตs-1.6ms70-90ยตs
Capabilities
Stateful ProcessingโŒโœ…โœ…
External Tool AccessโŒโœ…โœ…
Language ChoiceJS onlyAnyAny
Sandboxed Executionโœ…โŒDepends
Development ComplexityEasyEasyModerate

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

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 URL
  • r.method - HTTP method (GET, POST, etc.)
  • r.host - Hostname
  • r.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:

VariableDescriptionExample
HTTPJAIL_URLComplete request URLhttps://api.github.com/repos
HTTPJAIL_METHODHTTP methodGET, POST, PUT, etc.
HTTPJAIL_SCHEMEURL schemehttp or https
HTTPJAIL_HOSTHostname from URLapi.github.com
HTTPJAIL_PATHURL path/repos
HTTPJAIL_REQUESTER_IPIP of the requesting process127.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

  1. httpjail spawns your processor once at startup
  2. For each HTTP request, httpjail sends a JSON line to the processor's stdin
  3. The processor evaluates and responds with "true" or "false"
  4. 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

FeatureLinuxmacOSWindows
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 and HTTPS_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 tools
  • CURL_CA_BUNDLE - curl
  • REQUESTS_CA_BUNDLE - Python requests
  • NODE_EXTRA_CA_CERTS - Node.js
  • CARGO_HTTP_CAINFO - Cargo
  • GIT_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

  1. CA Generation: On first run, httpjail creates a unique CA keypair
  2. Certificate Storage: CA files are stored in your config directory:
    • Linux: ~/.config/httpjail/
    • macOS: ~/Library/Application Support/httpjail/
    • Windows: %APPDATA%\httpjail\ (planned)
  3. Process Trust: The jailed process trusts the CA via environment variables
  4. Per-Host Certificates: Each HTTPS connection gets a certificate signed by the httpjail CA
  5. 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 tools
  • CURL_CA_BUNDLE - curl
  • REQUESTS_CA_BUNDLE - Python requests
  • NODE_EXTRA_CA_CERTS - Node.js
  • CARGO_HTTP_CAINFO - Cargo
  • GIT_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

PlatformEnvironment VariablesSystem Trust Store
Linux๐ŸŸข Vast majorityN/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:

  1. Intercepts all DNS queries from the jailed process
  2. Returns dummy response (6.6.6.6) for every query
  3. Prevents external DNS access - queries never reach public resolvers
  4. 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:

  1. DNS Exfiltration Prevention: All DNS queries receive dummy response, never reaching public resolvers
  2. Blocked HTTP Traffic: Requests denied by rules without any DNS resolution
  3. 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.