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
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
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:
.ftw.yaml in the local folder or in your home folder (see YAML Config file for more information).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 absolutetestoverride : 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 flushedmaxmarkerloglines the maximum number of lines to search for a marker before abortingYou 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.
FTW tests are written in YAML format following a standardized schema. The complete schema documentation is maintained in the ftw-tests-schema repository.
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)
Each stage consists of: - input: The HTTP request to send - output: The expected response and log behavior
The input section supports these fields:
encoded_request insteadThe output section supports these validation fields:
expect_ids (default: false)---
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]
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.
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
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'
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
$ claude mcp add go-ftw \
-- python -m otcore.mcp_server <graph>