Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
http-garden — Differential testing framework for HTTP implementations | Kitploit
Tools/GitHubGitHub/narfindustries/http-garden
Vulnerability AnalysisDynamic Code Analysis (DAST)Web SecurityFuzzing
GitHubnarfindustries/http-garden

http-garden

Differential testing framework for HTTP implementations

View Repository
9418473 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

The HTTP Garden

The HTTP Garden is a collection of HTTP servers and proxies configured to be composable, along with scripts to interact with them in a way that makes finding vulnerabilities much much easier. For some cool demos of the vulnerabilities that you can find with the HTTP Garden, check out our ShmooCon 2024 talk.

Acknowledgements

We'd like to thank our friends at Galois, Trail of Bits, Narf Industries, and Dartmouth College for making this project possible.

This material is based upon work supported by the Defense Advanced Research Projects Agency (DARPA) under contract number HR0011-19-C-0076.

Getting Started

Dependencies

  1. The HTTP Garden runs on x86_64 and AArch64 Linux, and is untested on other platforms.
  2. The target servers are built and run in Docker containers, so you'll need Docker.
  3. You'll also need Python 3.12+ and the following Python packages, which you can get from PyPI (i.e. with pip) or from your system package manager:
  • docker
    • For interacting with Docker
  • pyyaml
Download Tool
  • For parsing yaml
  • tqdm
    • For progress bars
  • If you're installing Python packages with your system package manager, be aware that the package names may need to be prefixed with py3-, python3-, or python-, depending on the system.

    Running

    • Build and start up some servers and proxies:
    root@kitploit:~
    ./garden.sh start --build gunicorn hyper nginx haproxy
    
    • From another shell, start the repl:
    root@kitploit:~
    ./garden.sh repl
    
    • Send a basic GET request through HAProxy, then send the result to Gunicorn, Hyper, and Nginx origin servers, and display whether their interpretations match:
    root@kitploit:~
    garden> payload 'GET / HTTP/1.1\r\nHOST: a\r\n\r\n' | transduce haproxy | fanout | grid
    'GET / HTTP/1.1\r\nHOST: a\r\n\r\n'
    ⬇️ haproxy
    'GET / HTTP/1.1\r\nhost: a\r\n\r\n'
    gunicorn: [
        HTTPRequest(
            method=b'GET', uri=b'/', version=b'1.1',
            headers=[
                (b'host', b'a'),
            ],
            body=b'',
        ),
    ]
    hyper: [
        HTTPRequest(
            method=b'GET', uri=b'/', version=b'1.1',
            headers=[
                (b'host', b'a'),
            ],
            body=b'',
        ),
    ]
    nginx: [
        HTTPRequest(
            method=b'GET', uri=b'/', version=b'1.1',
            headers=[
                (b'host', b'a'),
                (b'content-length', b''),
                (b'content-type', b''),
            ],
            body=b'',
        ),
    ]
             g
             u
             n
             i h n
             c y g
             o p i
             r e n
             n r x
            +-----
    gunicorn|✓ ✓ ✓
    hyper   |  ✓ ✓
    nginx   |    ✓
    

    Seems like they all agree. (Note that even though Nginx added content-length and content-type headers, the Garden is aware of this and does not let this insignificant discrepancy show up in grid output.)

    Let's try a payload that uses a bare LF line ending in a chunked message body. This is disallowed in the spec.

    root@kitploit:~
    garden> payload 'POST / HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n0\n\r\n' | fanout | grid
    gunicorn: [
        HTTPResponse(version=b'1.1', method=b'400', reason=b'Bad Request'),
    ]
    hyper: [
    ]
    nginx: [
        HTTPRequest(
            method=b'POST', uri=b'/', version=b'1.1',
            headers=[
                (b'transfer-encoding', b'chunked'),
                (b'host', b'a'),
                (b'content-length', b'0'),
                (b'content-type', b''),
            ],
            body=b'',
        ),
    ]
             g
             u
             n
             i h n
             c y g
             o p i
             r e n
             n r x
            +-----
    gunicorn|✓ ✓ X
    hyper   |  ✓ X
    nginx   |    ✓
    

    Okay, so Gunicorn responded 400, Hyper didn't respond, and Nginx accepted. This is a violation of the spec by the Nginx authors that they don't care to fix.

    You may also have noticed that even though Gunicorn and Hyper didn't have exactly the same response, they showed as agreeing in the grid output earlier. This is because their responsees are essentially equivalent (a rejection of the message), and the Garden takes this into account.

    Directory Layout

    images

    The images directory contains a subdirectory for each HTTP server and transducer in the Garden. Each target gets its own Docker image. All programs are built from source when possible. So that we can easily build multiple versions of each target, all targets are paremetrized with a repository URL (APP_REPO), branch name (APP_BRANCH), and commit hash (APP_VERSION).

    tools

    The tools directory contains the scripts that are used to interact with the servers. Inside it, you'll find

    • probe_quirks.py: A script for enumerating benign HTTP parsing quirks in the systems under test to be ignored during fuzzing,
    • repl.py: The primary user interface to the HTTP Garden,
    • update.py: A script for updating the commit hashes in docker-compose.yml,
    • ...and a few more scripts that aren't user-facing.

    Targets

    HTTP Servers

    |-| | aiohttp | | apache_httpd | | apache_tomcat | | appweb | | aws_c_http | | cpp_httplib | | eclipse_grizzly | | eclipse_jetty | | fasthttp | | go_stdlib | | gunicorn | | h2o | | haproxy_fcgi | | hyper | | hypercorn | | ktor | | libevent | | libmicrohttpd | | libsoup | | lighttpd | | mongoose | | netty | | nginx | | node_stdlib | | openbsd_httpd | | openlitespeed | | openwrt_uhttpd | | protocol_http1 | | puma | | tornado | | twisted | | undertow | | uvicorn | | waitress | | webrick | | yahns |

    HTTP Transducers

    |-| | apache_httpd_proxy | | apache_traffic_server | | envoy | | go_stdlib_proxy | | h2o_proxy | | haproxy | | lighttpd_proxy | | nghttpx | | nginx_proxy | | openlitespeed_proxy | | pound | | squid | | varnish | | yahns_proxy |

    Omissions

    The following are explanations for a few notable omissions from the Garden:

    NameRationale
    Anything from MicrosoftMSRC told us "HTTP smuggling is not consider a vulnerability," and I feel no particular need to help Microsoft.
    unicornUses the same HTTP parser as yahns.
    SwiftNIOUses llhttp for HTTP parsing, which is already covered by node_stdlib.
    BunUses picohttpparser for HTTP parsing, which is already covered by h2o.
    DenoUses hyper for HTTP parsing, which is already in the Garden.
    DaphneUses twisted for HTTP parsing, which is already in the Garden.
    pitchforkUses the same parser as yahns.
    nghttpxUses lhttp for HTTP parsing, which is already covered by node_stdlib.
    CherootIgnores our reports.
    CherryPyUses cheroot for HTTP parsing.
    libhttpserverUses libmicrohttpd for HTTP parsing, which is already in the Garden.
    WerkzeugUses the CPython stdlib for HTTP parsing, which is already in the Garden.
    Caddy

    Results

    See TROPHIES.md for a complete list of bugs that the Garden has found.

    Uses the Go stdlib for HTTP parsing, which is already in the Garden.
    TengineUses Nginx's HTTP parser.
    OpenRestyUses Nginx's HTTP parser.
    Google Cloud Global External Application Load BalancerBased on Envoy.
    Google Cloud Regional External Application Load BalancerBased on Envoy.
    Phusion PassengerUses llhttpd for HTTP parsing, which is already covered by node_stdlib.
    passimUses libsoup for HTTP parsing, which is already in the Garden.
    boaUnmaintained.
    UlfiusUses libmicrohttpd, which is already in the Garden.
    Vultr Load BalancerIt's just HAProxy, which is already in the Garden.
    VMWare Avi Load BalancerIt's just Nginx, which is already in the Garden.
    SanicUses httptools, which is already covered by Uvicorn.
    CPython http.serverNot intended for production use.
    openjdk_stdlibProvides no coherent vulnerability disclosure channel.
    dart_stdlibIgnored prior reports.
    eventletHTTP library is just a fork of the one in the CPython stdlib.
    uwsgiDoesn't support chunked message bodies.