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.
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
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.
The limiting behavior depends on whether the request includes a 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)
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
// 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')#!/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()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
: trueLimit 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
: truePrevent 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- 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