Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/close-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ on:
schedule:
- cron: "30 1 * * *"

permissions: {}

jobs:
close-issues:
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ on:
pull_request:
schedule:
- cron: '0 6 * * 6'

permissions: {}

concurrency:
group: codeql-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read

steps:
- name: Checkout repository
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ on:
- cron: "05 14 * * *"
workflow_dispatch:

permissions: {}

jobs:
fuzz:
name: Fuzz tests
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6
with:
go-version: ">=1.24.0"
go-version: ">=1.25.0"
- run: go run mage.go fuzz
- run: |
gh issue create --title "$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER failed" \
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ on:
- "**/*.md"
- "LICENSE"

permissions: {}

concurrency:
group: lint-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
lint:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- name: Install Go
Expand Down
61 changes: 38 additions & 23 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,51 @@ on:
- "**/*.md"
- "LICENSE"
pull_request:
branches:
- main
paths-ignore:
- "**/*.md"
- "LICENSE"

jobs:
# Generate matrix of tags for all permutations of the tests
generate-matrix:
runs-on: ubuntu-latest
outputs:
tags: ${{ steps.generate.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
permissions: {}

concurrency:
group: regression-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

- name: Generate tag combinations
id: generate
run: |
go run mage.go tagsmatrix > tags.json
echo "tags=$(cat tags.json)" >> "$GITHUB_OUTPUT"
shell: bash
jobs:
test:
needs: generate-matrix
strategy:
fail-fast: false
matrix:
go-version: [1.24.x, 1.25.x]
go-version: [1.25.x]
os: [ubuntu-latest]
build-flag: ${{ fromJson(needs.generate-matrix.outputs.tags) }}
build-flag:
- ""
- "coraza.rule.mandatory_rule_id_check"
- "coraza.rule.case_sensitive_args_keys"
- "coraza.rule.no_regex_multiline"
- "coraza.no_memoize"
- "coraza.rule.multiphase_evaluation"
- "no_fs_access"
- "coraza.rule.multiphase_evaluation,coraza.rule.mandatory_rule_id_check"
- "coraza.rule.multiphase_evaluation,coraza.rule.case_sensitive_args_keys"
- "coraza.rule.multiphase_evaluation,coraza.rule.no_regex_multiline"
- "no_fs_access,coraza.no_memoize"
- "coraza.rule.mandatory_rule_id_check,coraza.rule.case_sensitive_args_keys,coraza.rule.no_regex_multiline"
- "coraza.rule.multiphase_evaluation,coraza.rule.mandatory_rule_id_check,coraza.rule.case_sensitive_args_keys,coraza.rule.no_regex_multiline,coraza.no_memoize,no_fs_access"
include:
- go-version: 1.26.x
os: ubuntu-latest
build-flag: ""
- go-version: 1.26.x
os: ubuntu-latest
build-flag: "coraza.rule.multiphase_evaluation,coraza.rule.mandatory_rule_id_check,coraza.rule.case_sensitive_args_keys,coraza.rule.no_regex_multiline,coraza.no_memoize,no_fs_access"
runs-on: ${{ matrix.os }}
permissions:
contents: read
env:
GOLANG_BASE_VERSION: "1.24.x"
GOLANG_BASE_VERSION: "1.25.x"
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
Expand All @@ -48,9 +62,9 @@ jobs:
go-version: ${{ matrix.go-version }}
cache: true
- name: Tests and coverage
run: |
export BUILD_TAGS=${{ matrix.build-flag }}
go run mage.go coverage
env:
BUILD_TAGS: ${{ matrix.build-flag }}
run: go run mage.go coverage
- name: "Codecov: General"
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5
if: ${{ matrix.go-version == env.GOLANG_BASE_VERSION }}
Expand Down Expand Up @@ -84,12 +98,13 @@ jobs:
runs-on: ubuntu-latest
permissions:
checks: read
contents: read
steps:
- name: GitHub Checks
uses: poseidon/wait-for-status-checks@899c768d191b56eef585c18f8558da19e1f3e707 # v0.6.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
delay: 120s # give some time to matrix jobs
delay: 30s
interval: 10s # default value
timeout: 3600s # default value
ignore: "codecov/patch,codecov/project"
14 changes: 11 additions & 3 deletions .github/workflows/tinygo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,23 @@ on:
- "**/*.md"
- "LICENSE"

permissions: {}

concurrency:
group: tinygo-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
strategy:
matrix:
go-version: [1.24.x]
go-version: [1.25.x]
# tinygo-version is meant to stay aligned with the one used in corazawaf/coraza-proxy-wasm
tinygo-version: [0.40.1]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
Expand Down Expand Up @@ -53,5 +61,5 @@ jobs:
- name: Tests
run: tinygo test -v -short ./internal/...

- name: Tests memoize
run: tinygo test -v -short -tags=memoize_builders ./internal/...
- name: Tests no_memoize
run: tinygo test -v -short -tags=coraza.no_memoize ./internal/...
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,11 @@ have compatibility guarantees across minor versions - use with care.
the operator with `plugins.RegisterOperator` to reduce binary size / startup overhead.
* `coraza.rule.multiphase_evaluation` - enables evaluation of rule variables in the phases that they are ready, not
only the phase the rule is defined for.
* `memoize_builders` - enables memoization of builders for regex and aho-corasick
dictionaries to reduce memory consumption in deployments that launch several coraza
instances. For more context check [this issue](https://github.com/corazawaf/coraza-caddy/issues/76)
* `coraza.no_memoize` - disables the default memoization of regex and aho-corasick builders.
Memoization is enabled by default and uses a global cache to reuse compiled patterns across WAF
instances, reducing memory consumption and startup overhead. In long-lived processes that perform
live reloads, use `WAF.Close()` (via `experimental.WAFCloser`) to release cached entries when a
WAF is destroyed, or use this tag to opt out of memoization entirely.
* `no_fs_access` - indicates that the target environment has no access to FS in order to not leverage OS' filesystem related functionality e.g. file body buffers.
* `coraza.rule.case_sensitive_args_keys` - enables case-sensitive matching for ARGS keys, aligning Coraza behavior with RFC 3986 specification. It will be enabled by default in the next major version.
* `coraza.rule.no_regex_multiline` - disables enabling by default regexes multiline modifiers in `@rx` operator. It aligns with CRS expected behavior, reduces false positives and might improve performances. No multiline regexes by default will be enabled in the next major version. For more context check [this PR](https://github.com/corazawaf/coraza/pull/876)
Expand Down
7 changes: 7 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type wafRule struct {
// int is a signed integer type that is at least 32 bits in size (platform-dependent size).
// We still basically assume 64-bit usage where int are big sizes.
type wafConfig struct {
ruleObserver func(rule types.RuleMetadata)
rules []wafRule
auditLog *auditLogConfig
requestBodyAccess bool
Expand All @@ -119,6 +120,12 @@ func (c *wafConfig) WithRules(rules ...*corazawaf.Rule) WAFConfig {
return ret
}

func (c *wafConfig) WithRuleObserver(observer func(rule types.RuleMetadata)) WAFConfig {
ret := c.clone()
ret.ruleObserver = observer
return ret
}

func (c *wafConfig) WithDirectivesFromFile(path string) WAFConfig {
ret := c.clone()
ret.rules = append(ret.rules, wafRule{file: path})
Expand Down
28 changes: 24 additions & 4 deletions coraza.conf-recommended
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ SecRule REQUEST_HEADERS:Content-Type "^application/json" \
SecRule REQUEST_HEADERS:Content-Type "^application/[a-z0-9.-]+[+]json" \
"id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"

# Configures the maximum JSON recursion depth limit Coraza will accept.
SecRequestBodyJsonDepthLimit 1024

# Enable JSON stream request body parser for NDJSON (Newline Delimited JSON) format.
# This processor handles streaming JSON where each line contains a complete JSON object.
# Commonly used for bulk data imports, log streaming, and batch API endpoints.
# Each JSON object is indexed by line number: json.0.field, json.1.field, etc.
#
#SecRule REQUEST_HEADERS:Content-Type "^application/x-ndjson" \
# "id:'200007',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSONSTREAM"
#
#SecRule REQUEST_HEADERS:Content-Type "^application/jsonlines" \
# "id:'200008',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSONSTREAM"
#
#SecRule REQUEST_HEADERS:Content-Type "^application/json-seq" \
# "id:'200010',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSONSTREAM"

# Maximum request body size we will accept for buffering. If you support
# file uploads, this value must has to be as large as the largest file
# you are willing to accept.
Expand Down Expand Up @@ -89,6 +106,9 @@ SecResponseBodyAccess On
# configuration below to catch documents but avoid static files
# (e.g., images and archives).
#
# Note: Add 'application/json' and 'application/x-ndjson' if you want to
# inspect JSON and NDJSON response bodies
#
SecResponseBodyMimeType text/plain text/html text/xml

# Buffer response bodies of up to 512 KB in length.
Expand Down Expand Up @@ -118,11 +138,11 @@ SecDataDir /tmp/
#
#SecUploadDir /opt/coraza/var/upload/

# If On, the WAF will store the uploaded files in the SecUploadDir
# directory.
# Note: SecUploadKeepFiles is currently NOT supported by Coraza
# Controls whether intercepted uploaded files will be kept after
# transaction is processed. Possible values: On, Off, RelevantOnly.
# RelevantOnly will keep files only when a matching rule is logged (rules with 'nolog' do not qualify).
#
#SecUploadKeepFiles Off
#SecUploadKeepFiles RelevantOnly

# Uploaded files are by default created with permissions that do not allow
# any other user to access them. You may need to relax that if you want to
Expand Down
10 changes: 5 additions & 5 deletions examples/http-server/go.mod
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
module github.com/corazawaf/coraza/v3/examples/http-server

go 1.24.0
go 1.25.0

require github.com/corazawaf/coraza/v3 v3.3.3

require (
github.com/corazawaf/libinjection-go v0.2.2 // indirect
github.com/corazawaf/libinjection-go v0.3.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/magefile/mage v1.15.1-0.20250615140142-78acbaf2e3ae // indirect
github.com/petar-dambovaliev/aho-corasick v0.0.0-20250424160509-463d218d4745 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/valllabh/ocsf-schema-golang v1.0.3 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/tools v0.35.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/tools v0.42.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
rsc.io/binaryregexp v0.2.0 // indirect
)
24 changes: 12 additions & 12 deletions examples/http-server/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc h1:Ol
github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc/go.mod h1:7rsocqNDkTCira5T0M7buoKR2ehh7YZiPkzxRuAgvVU=
github.com/corazawaf/coraza/v3 v3.3.3 h1:kqjStHAgWqwP5dh7n0vhTOF0a3t+VikNS/EaMiG0Fhk=
github.com/corazawaf/coraza/v3 v3.3.3/go.mod h1:xSaXWOhFMSbrV8qOOfBKAyw3aOqfwaSaOy5BgSF8XlA=
github.com/corazawaf/libinjection-go v0.2.2 h1:Chzodvb6+NXh6wew5/yhD0Ggioif9ACrQGR4qjTCs1g=
github.com/corazawaf/libinjection-go v0.2.2/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw=
github.com/corazawaf/libinjection-go v0.3.2 h1:9rrKt0lpg4WvUXt+lwS06GywfqRXXsa/7JcOw5cQLwI=
github.com/corazawaf/libinjection-go v0.3.2/go.mod h1:Ik/+w3UmTWH9yn366RgS9D95K3y7Atb5m/H/gXzzPCk=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
Expand All @@ -25,16 +25,16 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/valllabh/ocsf-schema-golang v1.0.3 h1:eR8k/3jP/OOqB8LRCtdJ4U+vlgd/gk5y3KMXoodrsrw=
github.com/valllabh/ocsf-schema-golang v1.0.3/go.mod h1:sZ3as9xqm1SSK5feFWIR2CuGeGRhsM7TR1MbpBctzPk=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
Expand Down
Loading