Skip to main content

Botgate

Botgate is an evidence-first conformance and coverage analyzer for Web Bot Auth and RFC 9421 HTTP Message Signatures.

It answers four separate questions:

  1. Is the message shaped correctly for a selected protocol profile?
  2. Does the signature verify with an explicitly supplied key?
  3. Which request properties are cryptographically bound?
  4. Does that coverage satisfy the application's declared policy?

Botgate deliberately does not infer authentication from an HTTP status code. A 200 response is not evidence that a server accepted a signature; the resource may simply be public.

Status

This repository implements a focused v0.1:

  • current draft-ietf-webbotauth-httpsig-protocol-00 inspection;
  • the current Cloudflare compatibility profile;
  • current dictionary-form and legacy string-form Signature-Agent handling;
  • RFC 9421 signature-base reconstruction for the common request components;
  • RFC 8941 canonicalization for selected Structured Field dictionary members;
  • Ed25519 signing and verification;
  • JWK thumbprint/key selection;
  • semantic coverage and configurable policy evaluation;
  • Content-Digest SHA-256 validation;
  • JSON output for CI;
  • a safe offline mutation matrix.

It does not fetch untrusted key-directory URLs or send active mutations. Those operations require an SSRF-safe resolver and an explicit authentication oracle; pretending that response status alone is an oracle would produce misleading results.

Install

You do not need Rust or Cargo to use Botgate.

On macOS or Linux, install with Homebrew:

brew install kraftaa/tap/botgate

If you already use Python tooling, install the same native Botgate binary on macOS, Linux, or Windows with pipx:

pipx install botgate

Or with uv:

uv tool install botgate

Inside an existing Python virtual environment, ordinary pip works too:

python -m pip install botgate

These package-manager installs use prebuilt native binaries; they do not compile Botgate or install a Rust toolchain. Standalone archives, a Windows installer, a shell installer, and SHA-256 checksums are also available on the Releases page as fallbacks.

The download links become active when the first public release is published. Until then, authenticated repository collaborators can download private release assets with the GitHub CLI.

Confirm the installation:

botgate --version
botgate --help

End-to-end example

Generate a test key and policy:

botgate init

This creates:

.botgate/
├── private.key       # Ed25519 PKCS#8, mode 0600 on Unix
├── public.jwk
├── directory.json
└── botgate.toml

The whole .botgate/ directory is excluded by .gitignore. Botgate never prints the private key. A conformant remote key directory must be served over HTTPS.

Running botgate init --force regenerates public.jwk and directory.json from the existing private key. It never overwrites private.key or an existing botgate.toml.

On Unix, the private key is created atomically with mode 0600. On Windows it is created with create_new but inherits the directory's ACL; restrict access to .botgate/ yourself.

Sign the example request using the current IETF form:

botgate sign examples/request.http \
  --agent https://agent.example \
  --components @authority,@method,@path,@query \
  --output signed-request.http

Inspect declared coverage without loading a key:

botgate inspect signed-request.http \
  --config examples/strict-policy.toml

Verify cryptographically using a local JWKS:

botgate verify signed-request.http \
  --jwks .botgate/directory.json \
  --config examples/strict-policy.toml

Show the offline mutation matrix:

botgate test signed-request.http \
  --jwks .botgate/directory.json \
  --config examples/strict-policy.toml

Nothing is sent by test. In particular, Botgate never turns a GET into a live POST or DELETE request. The matrix is generated independently for every signature in the request.

Cloudflare interoperability

The September 2026 working-group draft requires new senders to emit dictionary-form Signature-Agent, keyed by the signature label:

Signature-Agent: sig1="https://agent.example"
Signature-Input: sig1=("@authority" "signature-agent";key="sig1");...

Cloudflare currently documents the older bare-string form. Generate and analyze that form explicitly:

botgate sign examples/request.http \
  --agent https://agent.example \
  --components @authority \
  --legacy-agent \
  --output cloudflare-request.http

botgate inspect cloudflare-request.http --profile cloudflare
botgate inspect cloudflare-request.http --profile ietf-draft-00

The second command reports why the same request is legacy rather than conformant for a new IETF-draft sender.

Policy

Policy requirements are application requirements, not claims that every conforming Web Bot Auth signature must cover the same fields. Without --config, Botgate automatically loads .botgate/botgate.toml from the current directory when it exists; otherwise it uses the same built-in defaults produced by init. Every report names the policy it applied (Policy: in text, policy_source in JSON). In CI, pass --config explicitly so a change to .botgate/ cannot silently alter the gate. Unknown keys and negative time limits are rejected.

[policy]
require_authority = true
require_method = true
require_path = true
query = "required"
body = "ignore"
max_age_seconds = 300
max_lifetime_seconds = 300
allowed_future_skew_seconds = 30
require_nonce = false

Coverage is semantic rather than a flat string check. For example, @target-uri satisfies authority, path, and query coverage, while @path does not cover the query. Body integrity requires a covered Content-Digest (the whole field, or its sha-256 member via ;key="sha-256") whose SHA-256 value matches the body bytes. Covering only another member, such as sha-512, does not count. Individual @query-param components are reported as partial evidence and do not satisfy a policy requiring the entire query to be bound. @request-target covers path and query for the raw HTTP/1.1 requests accepted by v0.1.

JSON and exit behavior

Use --format json with inspect, verify, or test.

botgate inspect request.http --format json

Exit status is 0 when no error-level findings exist, 1 when conformance, compatibility, crypto, or policy findings fail, and 4 for input or configuration errors detected after argument parsing. Clap uses its conventional status 2 for command-line usage errors. JSON retains independent finding categories and cryptographic/identity states so CI does not need to infer meaning from prose.

Trust model

Verification with --jwks establishes that the supplied key validates the signature. It intentionally reports identity as key_only: loading a local JWK does not prove that an HTTPS Signature-Agent URL published that key. URL attribution requires a safe HTTPS discovery operation and its cache state.

The signing command derives the thumbprint from the private key and refuses to proceed if --jwk names a different key pair.

Similarly, signing Content-Digest binds the digest header. Botgate separately recomputes the digest before reporting body integrity.

Supported signature components

v0.1 reconstructs:

  • @method
  • @authority
  • @scheme
  • @path
  • @query
  • @target-uri
  • @request-target
  • @query-param;name=...
  • ordinary HTTP fields
  • dictionary field members selected with ;key=...

Unsupported derived components cause verification to fail explicitly rather than being guessed. Input files use a strict raw HTTP/1.0 or HTTP/1.1 request format; malformed control data, folded headers, and ambiguous authorities are rejected before analysis.

Non-goals

Botgate does not impersonate commercial agents, bypass bot protection, solve CAPTCHAs, crawl sites, score “AI readiness,” or replace authorization and bot-management systems.

Development

Rust and Cargo are required only when building Botgate from source or contributing to the project:

cargo build --release
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
cargo deny check

The minimum supported Rust version is 1.86. CI runs the test suite on Linux, macOS, and Windows.

cargo test includes property tests for the HTTP and Structured Fields parsers. Coverage-guided fuzz targets live in fuzz/ and need a nightly toolchain and cargo-fuzz:

cargo install cargo-fuzz
cargo +nightly fuzz run parse_request
cargo +nightly fuzz run parse_signatures
cargo +nightly fuzz run signature_base

See SECURITY.md for the trust model and how to report vulnerabilities. Maintainer release setup is documented in RELEASING.md.

The protocol is still an Internet-Draft. Profile-specific behavior is kept separate in the report engine, and botgate protocol identifies the implemented draft.

References

Metadata

Release files for botgate 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for botgate 0.1.0
File
botgate-0.1.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
botgate-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
botgate-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
botgate-0.1.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
botgate-0.1.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 4.5 MB

Release files / botgate-0.1.0-py3-none-win_amd64.whl

Download URL botgate-0.1.0-py3-none-win_amd64.whl
Size 980.9 kB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
e995f03a122df8321cf5dcef01a16fb27f66d9e3ae1497c354767a336e1d89f0
BLAKE2b-256 checksum
How to use checksums
500df627912c79f98e78a97aab765028a27b5a7f990b695dc01b61e2c0d51dfe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / botgate-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL botgate-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 909.9 kB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
a4626ef9b9642a460918e6cfba82930ec363274f715a39e4c19f882f1f1c24bc
BLAKE2b-256 checksum
How to use checksums
d4dd47f674912dd9e226c3cbe2eca2b5475d3c9af5ce5f209beed3fd62a487a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / botgate-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL botgate-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 870.0 kB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
9ed0cb3a7e7d5e9c9f080f7ee1608561c00b9c81ebf726fc4dbc3695ba1579fb
BLAKE2b-256 checksum
How to use checksums
a1183867a3a3f141a6efe6b745218ebf7bfdd092e342205b1a3e7a53bd2c982f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / botgate-0.1.0-py3-none-macosx_11_0_arm64.whl

Download URL botgate-0.1.0-py3-none-macosx_11_0_arm64.whl
Size 845.7 kB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c3a3e286f7bdfdbd874ff516702ffa67b650970a6a126f600777c70c5d201133
BLAKE2b-256 checksum
How to use checksums
64ccb4c83f873265e6b389b4e2da8734ad21a5e86aca5f278c123d7a87a760ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / botgate-0.1.0-py3-none-macosx_10_12_x86_64.whl

Download URL botgate-0.1.0-py3-none-macosx_10_12_x86_64.whl
Size 894.1 kB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
7a12d1fe2eb1f60cf491ad6d2970786bb642e5ef2e3af4d64b6a7fa4b3dbe4f6
BLAKE2b-256 checksum
How to use checksums
ee5e7dfe9ec88d4eea0a9a60797880ea0e515bf976235e17b1fcf675ef2b570b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.1

5 release files

0.2.0

5 release files

This release

0.1.0 This release

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page