MCPcopy Index your code
hub / github.com/coreruleset/go-ftw

github.com/coreruleset/go-ftw @v2.4.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.4.0 ↗ · + Follow
838 symbols 3,151 edges 98 files 288 documented · 34% 1 cross-repo links
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Go-FTW - Framework for Testing WAFs in Go!

pre-commit Go Report Card Go Doc PkgGoDev Release Coverage Quality Gate Status OpenSSF Scorecard

Go-FTW is a replacement for FTW which had reached its limits in terms of maintainability and performance.

Features of Go-FTW include: - fully customizable HTTP traffic - CI/CD friendly - fast - syntax checking of test files

Install

Go to the releases page and get a binary release that matches your OS (scroll down to Assets).

If you have Go installed and configured to run Go binaries from your shell you can also run

go install github.com/coreruleset/go-ftw@latest

Example Usage

The go-ftw is designed to run Web Application Firewall (WAF) unit tests. The primary focus is the OWASP ModSecurity Core Rule Set.

In order to run the tests, you need to prepare the following:

  1. Active WAF
  2. Log where the WAF writes the alert messages
  3. go-ftw config file .ftw.yaml in the local folder or in your home folder (see YAML Config file for more information).
  4. At least one unit test in (go)-ftw's yaml format.

YAML Config file

With the configuration, you can set paths for your environment, enable and disable features and you can also use it to alter the test results.

The config file has six basic settings:

  • logfile : path to WAF log with alert messages, relative or absolute
  • testoverride : a list of things to override (see Overriding tests below)
  • mode : "default" or "cloud" (only change it if you need "cloud")
  • logmarkerheadername : name of an HTTP header used for marking log messages, usually X-CRS-TEST (see How log parsing works below)
  • maxmarkerretries : the maximum number of times the search for log markers will be repeated; each time an additional request is sent to the web server, eventually forcing the log to be flushed
  • maxmarkerloglines the maximum number of lines to search for a marker before aborting

You can probably leave the last three alone, they are set to sane defaults.

Example with absolute logfile:

logfile: /apache/logs/error.log
logmarkerheadername: X-CRS-TEST
testoverride:
mode: "default"

Example with relative logfile:

logfile: ../logs/error.log
logmarkerheadername: X-CRS-TEST
testoverride:
mode: "default"

Example with minimal definitions:

The minimal requirement for go-ftw is to have a logfile when running in default mode:

logfile: ../logs/error.log

By default, go-ftw looks for a file in $PWD / local folder with the name .ftw.yaml. If this can not be found, it will look in the user's HOME folder. You can pass the --config <config file name> to point it to a different file.

Test File Format

FTW tests are written in YAML format following a standardized schema. The complete schema documentation is maintained in the ftw-tests-schema repository.

Basic Test Structure

A test file contains: - meta: Metadata about the test file (author, description, name, tags) - rule_id: The rule ID being tested - tests: An array of test cases

Each test case includes: - test_id: (Optional) Sequence number of the test for the rule specified by rule_id. When not set, the ID will be inferred from the position. - test_title: (Optional) Human-readable title used for inclusion/exclusion of test runs - desc: (Optional) Description of what the test does - tags: (Optional) Array of tags for filtering tests - stages: Array of test stages (request/response pairs)

Test Stages

Each stage consists of: - input: The HTTP request to send - output: The expected response and log behavior

Input Fields

The input section supports these fields:

  • dest_addr: Destination address (IP or hostname)
  • port: Port number
  • protocol: Protocol (http/https)
  • uri: Request URI
  • follow_redirect: If true, follows redirect from previous stage (ignores port, protocol, address, URI)
  • version: HTTP version (e.g., "HTTP/1.1")
  • method: HTTP method (GET, POST, etc.)
  • headers: Map of HTTP headers
  • data: Request body data as plain string
  • encoded_data: Request body data as base64 encoded string (allows complex payloads with invisible characters)
  • encoded_request: Base64 encoded full HTTP request (overrides all other settings)
  • save_cookie: Save cookies from response for subsequent requests
  • autocomplete_headers: Auto-add common headers (Connection, Content-Length, Content-Type). Defaults to true.
  • stop_magic: (Deprecated) No longer used
  • raw_request: (Deprecated) Use encoded_request instead
Output Fields

The output section supports these validation fields:

  • status: Expected HTTP status code
  • response_contains: String that should appear in response body
  • log_contains: String that should appear in WAF logs
  • no_log_contains: String that should NOT appear in WAF logs
  • log: Object containing log validation fields:
  • expect_ids: Array of rule IDs expected to trigger
  • no_expect_ids: Array of rule IDs that should NOT trigger
  • match_regex: Regular expression expected to match log content
  • no_match_regex: Regular expression that should NOT match log content
  • expect_error: Boolean, whether an error is expected (no response from WAF)
  • retry_once: Retry the test once if it fails (useful for phase 5 race conditions)
  • isolated: Boolean, test should trigger only the single rule specified in expect_ids (default: false)

Example Test

---
meta:
  author: "OWASP CRS"
  description: "Test for SQL Injection Detection"
  name: "942100.yaml"
rule_id: 942100
tests:
  - test_id: 1
    desc: "SQL Injection via UNION SELECT"
    stages:
      - input:
          dest_addr: "localhost"
          port: 80
          headers:
            User-Agent: "ModSecurity CRS 3 Tests"
            Host: "localhost"
          uri: "/index.html?id=1' UNION SELECT NULL--"
          method: "GET"
        output:
          status: 403
          log:
            expect_ids: [942100]
  - test_id: 2
    desc: "Benign request should pass"
    stages:
      - input:
          dest_addr: "localhost"
          port: 80
          headers:
            User-Agent: "ModSecurity CRS 3 Tests"
            Host: "localhost"
          uri: "/index.html?id=123"
          method: "GET"
        output:
          status: 200
          log:
            no_expect_ids: [942100]

Using Templates

Go-FTW supports Go templates and Sprig functions in test data:

# Generate repeated characters
data: 'foo=%3d{{ "+" | repeat 34 }}'

# Read from environment
data: 'username={{ env "USERNAME" }}'

# Use random data
data: 'token={{ randAlphaNum 32 }}'

For complete schema documentation including all available fields and options, see the FTW Tests Schema Documentation.

WAF Server

I normally perform my testing using the Core Rule Set.

You can start the containers from that repo using docker compose:

git clone https://github.com/coreruleset/coreruleset.git
cd coreruleset
docker compose -f tests/docker-compose.yml up -d modsec2-apache

Logfile

Running in default mode implies you have access to a logfile for checking the WAF behavior against test results. For this example, assuming you are in the base directory of the coreruleset repository, these are the configurations for apache and nginx:

---
logfile: 'tests/logs/modsec2-apache/error.log'
---
logfile: 'tests/logs/modsec3-nginx/error.log'

Running

This is the help for the run command: ```bash go-ftw run --help Run all tests below a certain subdirectory. The command will search all y[a]ml files recursively and pass it to the test engine.

Usage: go-ftw run [flags]

Flags: --connect-timeout duration timeout for connecting to endpoints during test execution (default 3s) -d, --dir string recursively find yaml tests in this directory (default ".") -e, --exclude string exclude tests matching this Go regular expression (e.g. to exclude all tests beginning with "91", use "^91."). If you want more permanent exclusion, check the 'exclude' option in the config file. --fail-fast Fail on first failed test --failure-waf-logs-dir string directory path for failure-waf-logs-file; defaults to the same directory as the WAF log file; see (log-file); see store-failure-waf-logs and failure-waf-logs-file --failure-waf-logs-file string file name for WAF log entries for failed tests; defaults to 'go-ftw-failure-waf-logs.log'; see store-failure-waf-logs and failure-waf-logs-dir (default "go-ftw-failure-waf-logs.log") -f, --file string output file path for ftw tests. Prints to standard output by default. -g, --glob string override the filename glob pattern for matching test files (default ".yml") -h, --help help for run -i, --include string include only tests matching this Go regular expression (e.g. to include only tests beginning with "91", use "^91."). If you want more permanent inclusion, check the 'include' option in the config file. -T, --include-tags string include tests tagged with labels matching this Go regular expression (e.g. to include all tests being tagged with "cookie", use "^cookie$"). -l, --log-file string path to log file to watch for WAF events --max-marker-log-lines uint maximum number of lines to search for a marker before aborting (default 500) --max-marker-retries uint maximum number of times the search for log markers will be repeated. Each time an additional request is sent to the web server, eventually forcing the log to be flushed (default 20) -o, --output string output type for ftw tests. "normal" is the default. (default "normal") -r, --rate-limit duration Limit the request rate to the server to 1 request per specified duration. 0 is the default, and disables rate limiting. --read-timeout duration timeout for receiving responses during test execution (default 10s) --report-triggered-rules Report triggered rules for each test --show-failures-only shows only the results of failed tests --skip-tls-verification Skips TLS certificate checks. Useful for testing domains with self-signed TLS ceritificates. --store-failure-waf-logs saves WAF log entries for failed tests to a dedicated file, configureable through failure-waf-logs-file and failure-waf-logs-dir -t, --time show time spent per test --wait-delay duration Time to wait between retries for all wait operations. (default 1s) --wait-for-connection-timeout duration Http connection timeout, The timeout includes connection time, any redirects, and reading the response body. (default 3s) --wait-for-expect-body-json string Expect response body JSON pattern. --wait-for-expect-body-regex string Expect response body pattern. --wait-for-expect-body-xpath string Expect response body XPath pattern. --wait-for-expect-header string Expect response header pattern. --wait-for-expect-status-code int Expect response code e.g. 200, 204, ... . --wait-for-host string Wait for host to be available before running tests. --wait-for-no-redirect Do not follow HTTP 3xx redirects. --wait-for-timeout duration Sets the timeout for all wait operations, 0 is unlimited. (default 10s)

Global Flags: --cloud cloud mode: rely only on HTTP status codes for determining test success or failure (will not process any logs) --config string specify config file (default is $PWD/.ftw.yaml) --debug debug output --overrides string specify file with platfo

Extension points exported contracts — how you extend this code

File (Interface)
File interface is used to interact with Corpus files. It provides methods for setting the cache directory and file path. [2 …
internal/corpus/types.go
LocalEngine (Interface)
LocalEngine is the interface for the local engine [1 implementers]
internal/quantitative/local_engine.go
FTWConnection (Interface)
FTWConnection is the interface method implement to send and receive data [1 implementers]
ftwhttp/types.go
Corpus (Interface)
Corpus is the interface that must be implemented to make a corpus available to clients [2 implementers]
internal/corpus/types.go
Iterator (Interface)
Iterator is an interface for iterating over a corpus [2 implementers]
internal/corpus/types.go
Payload (Interface)
(no doc) [2 implementers]
internal/corpus/types.go

Core symbols most depended-on inside this repo

Add
called by 52
ftwhttp/header.go
NewInput
called by 41
test/defaults.go
TotalFailed
called by 31
runner/stats.go
GetAll
called by 30
ftwhttp/header.go
CreateTempFileWithContent
called by 29
utils/tests.go
AssertLogs
called by 29
runner/check_logs.go
NewHeader
called by 27
ftwhttp/header.go
Println
called by 26
output/output.go

Shape

Method 574
Function 162
Struct 89
TypeAlias 7
Interface 6

Languages

Go100%

Modules by API surface

runner/run_test.go35 symbols
internal/corpus/types.go31 symbols
config/config_test.go24 symbols
ftwhttp/request_test.go23 symbols
cmd/run/run_test.go23 symbols
test/types_test.go22 symbols
cmd/internal/flag_types.go20 symbols
waflog/read_test.go19 symbols
runner/run_input_override_test.go18 symbols
ftwhttp/client_test.go18 symbols
internal/quantitative/leipzig/corpus.go17 symbols
runner/stats_test.go16 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

For agents

$ claude mcp add go-ftw \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact