Skip to content

Releases: DataDog/libddwaf

v2.0.1

Choose a tag to compare

@github-actions github-actions released this 02 Jul 16:33
Immutable release. Only release title and notes can be modified.
affa189

v2.0.1

Release Changelog

Changes

  • Use inline storage for value iterators (#502).

Fixes

  • Avoid exception in user resource comparison (#501).
  • Preserve relative path of source files in logs (#500).
  • Fix warnings when building for wasm32 (#499).
  • Fix bad has_from_chars concept (#497).

Miscellaneous

  • Remove CodeCov upload from CI (#498).

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 12 Jun 13:12
Immutable release. Only release title and notes can be modified.
c5fdbb3

v2.0.0

libddwaf v2.0.0 represents a significant redesign of the C API, focusing on explicit memory ownership, reduced memory footprint, and a more consistent interface. Beyond the public API, the internals have also been refactored to use safer and more C++-native abstractions.

As expected, this release is not backwards compatible; the upgrading guide at docs/upgrading/UPGRADING-v2.0.md provides detailed migration examples for each of the breaking changes.

Memory Ownership and Allocators

The most fundamental change in v2 is the introduction of allocators throughout the API. In v1, memory ownership across the API boundary was often ambiguous, leading to potential issues in complex integration scenarios. The new allocator system makes memory ownership explicit: callers provide an allocator when creating objects and use the same allocator when destroying them. A default allocator is available via ddwaf_get_default_allocator() for simple use cases, while custom allocators enable advanced memory management strategies.

Object Model and Creation API

The ddwaf_object structure has been completely redesigned to reduce memory overhead. A single object now requires only 16 bytes, down from a considerably larger footprint in v1. This was achieved through carefully redesigning each of the possible type variants and, more specifically, through the removal of map keys from the main ddwaf_object in favour of representing maps through a separate ddwaf_object_kv structure. Indirectly, this new version enables further reduction in the memory and allocations through the introduction of small strings, where strings of 14 bytes or fewer are stored directly within the object without additional heap allocation, and literal strings, which reference read-only memory that is never freed by the library.

Object creation functions have been renamed to follow a consistent ddwaf_object_set_* pattern and now require an allocator parameter where allocation may occur. Container insertion returns a pointer to the newly inserted element, eliminating the need for intermediate objects. For example, where v1 required creating a value object separately and then adding it to a map, v2 allows direct initialisation: ddwaf_object_set_string(ddwaf_object_insert_key(&map, "key", 3, alloc), "value", 5, alloc). This pattern reduces boilerplate and makes the ownership model clearer.

Context and Subcontext Lifecycle

The function ddwaf_run has been renamed to ddwaf_context_eval for consistency with the rest of the API. More significantly, ephemeral data semantics have been replaced with a new subcontext mechanism. In v1, ephemeral data was passed as a separate parameter to each ddwaf_run call and was not retained. In v2, a subcontext is explicitly created from a parent context via ddwaf_subcontext_init, evaluated with ddwaf_subcontext_eval, and destroyed with ddwaf_subcontext_destroy. Subcontexts inherit all data from their parent context but maintain their own isolated evaluation state. Multiple concurrent subcontexts can be created from the same parent context, each defining its own data scope and lifetime.

Release Changelog

Changes

  • Object model overhaul: immutable object_view, owned/borrowed writable objects, raw configuration on object_view, container view types, and updated unit tests (#341, #378, #382, #387, #390, #391, #394, #408, #413, #476).
  • Allocator API: propagate allocators through contexts/subcontexts, expose allocator-aware interfaces, and stop generating zero-terminated strings (#418, #420, #427, #452).
  • Refactored evaluation lifecycle: separated data insertion from evaluation and lifted evaluation stages out of the context (#407, #442).
  • Subcontexts with user-defined lifetimes and validator support for subcontexts/attributes (#443, #451, #468).
  • Array indexing on key paths (#458).
  • Instantiate obfuscator through configuration and remove ddwaf_config (#464).
  • Return DDWAF_MATCH when events, attributes, or actions are present (#455).
  • Remove legacy configuration schema (v1) support (#482).
  • Introduce ddwaf_(context|subcontext)_multieval to evaluate multiple batches in sequence (#494).

Fixes

  • Report input attribute addresses on ddwaf_known_addresses (#485).
  • Remove default allocator arguments (#486).

Miscellaneous

  • Upgrade fmt dependency and use as header-only (#478).
  • Increase macOS target to 14.2.1 (#477).
  • Add option to build on valgrind to avoid RE2 UB noise (#480).
  • Lint all headers and add tests (#474).
  • Intertwine context and subcontext calls within benchmark (#469).
  • Disable unreliable GCC / Clang benchmarks (#470).
  • Upload coverage reports to Datadog (#471).
  • Remove mingw builds (#381).
  • Cleanup exclusion namespace and redundant references (#456).
  • Expanded fingerprint and object-view tests (#414).
  • Add fuzzer v2 (#465).
  • Update logger to avoid dependencies on ddwaf.h (#453).
  • Achieve 100% test coverage for src/utils.cpp (#481).
  • Documentation (#487).

v2.0.0-alpha0

Choose a tag to compare

@github-actions github-actions released this 21 Jan 18:24
Immutable release. Only release title and notes can be modified.
cf49c49

libddwaf v2.0.0 represents a significant redesign of the C API, focusing on explicit memory ownership, reduced memory footprint, and a more consistent interface. Beyond the public API, the internals have also been refactored to use safer and more C++-native abstractions. This is an alpha release intended for early adopters and binding library maintainers to begin integration work.

As expected, this release is not backwards compatible; the upgrading guide at docs/upgrading/UPGRADING-v2.0.md provides detailed migration examples for each of the breaking changes.

Memory Ownership and Allocators

The most fundamental change in v2 is the introduction of allocators throughout the API. In v1, memory ownership across the API boundary was often ambiguous, leading to potential issues in complex integration scenarios. The new allocator system makes memory ownership explicit: callers provide an allocator when creating objects and use the same allocator when destroying them. A default allocator is available via ddwaf_get_default_allocator() for simple use cases, while custom allocators enable advanced memory management strategies.

Object Model and Creation API

The ddwaf_object structure has been completely redesigned to reduce memory overhead. A single object now requires only 16 bytes, down from a considerably larger footprint in v1. This was achieved through carefully redesigning each of the possible type variants and, more specifically, through the removal of map keys from the main ddwaf_object in favour of representing maps through a separate ddwaf_object_kv structure. Indirectly, this new version enables further reduction in the memory and allocations through the introduction of small strings, where strings of 14 bytes or fewer are stored directly within the object without additional heap allocation, and literal strings, which reference read-only memory that is never freed by the library.

Object creation functions have been renamed to follow a consistent ddwaf_object_set_* pattern and now require an allocator parameter where allocation may occur. Container insertion returns a pointer to the newly inserted element, eliminating the need for intermediate objects. For example, where v1 required creating a value object separately and then adding it to a map, v2 allows direct initialisation: ddwaf_object_set_string(ddwaf_object_insert_key(&map, "key", 3, alloc), "value", 5, alloc). This pattern reduces boilerplate and makes the ownership model clearer.

Context and Subcontext Lifecycle

The function ddwaf_run has been renamed to ddwaf_context_eval for consistency with the rest of the API. More significantly, ephemeral data semantics have been replaced with a new subcontext mechanism. In v1, ephemeral data was passed as a separate parameter to each ddwaf_run call and was not retained. In v2, a subcontext is explicitly created from a parent context via ddwaf_subcontext_init, evaluated with ddwaf_subcontext_eval, and destroyed with ddwaf_subcontext_destroy. Subcontexts inherit all data from their parent context but maintain their own isolated evaluation state. Multiple concurrent subcontexts can be created from the same parent context, each defining its own data scope and lifetime.

Release Changelog

Changes

  • Object model overhaul: immutable object_view, owned/borrowed writable objects, raw configuration on object_view, container view types, and updated unit tests (#341, #378, #382, #387, #390, #391, #394, #408, #413, #476).
  • Allocator API: propagate allocators through contexts/subcontexts, expose allocator-aware interfaces, and stop generating zero-terminated strings (#418, #420, #427, #452).
  • Refactored evaluation lifecycle: separated data insertion from evaluation and lifted evaluation stages out of the context (#407, #442).
  • Subcontexts with user-defined lifetimes and validator support for subcontexts/attributes (#443, #451, #468).
  • Array indexing on key paths (#458).
  • Instantiate obfuscator through configuration and remove ddwaf_config (#464).
  • Return DDWAF_MATCH when events, attributes, or actions are present (#455).
  • Remove legacy configuration schema (v1) support (#482).

Fixes

  • Report input attribute addresses on ddwaf_known_addresses (#485).
  • Remove default allocator arguments (#486).

Miscellaneous

  • Upgrade fmt dependency and use as header-only (#478).
  • Increase macOS target to 14.2.1 (#477).
  • Add option to build on valgrind to avoid RE2 UB noise (#480).
  • Lint all headers and add tests (#474).
  • Intertwine context and subcontext calls within benchmark (#469).
  • Disable unreliable GCC / Clang benchmarks (#470).
  • Upload coverage reports to Datadog (#471).
  • Remove mingw builds (#381).
  • Cleanup exclusion namespace and redundant references (#456).
  • Expanded fingerprint and object-view tests (#414).
  • Add fuzzer v2 (#465).
  • Update logger to avoid dependencies on ddwaf.h (#453).
  • Achieve 100% test coverage for src/utils.cpp (#481).
  • Documentation (#487).

v1.30.1 (unstable)

Choose a tag to compare

@github-actions github-actions released this 11 Dec 14:31
Immutable release. Only release title and notes can be modified.
da7fd66

Note

The minimum MacOS target has been increased to 14.2.1 due to the deprecation of the macos-13 github runner.

Fixes

  • Report input attribute addresses on ddwaf_known_addresses (#484)

v1.30.0 (unstable)

Choose a tag to compare

@github-actions github-actions released this 28 Oct 10:25
Immutable release. Only release title and notes can be modified.
00e895f

This release introduces no new features, however the recently introduced block_id action parameter has been renamed to security_response_id for consistency.

Release changelog

Changes

  • Rename block_id to security_response_id (#473)

v1.29.0 (unstable)

Choose a tag to compare

@github-actions github-actions released this 01 Oct 09:54
bea83f9

New Features

This release introduces a focused set of features addressing the most pressing use cases. Barring any necessary patch releases, this will constitute the final v1.x release.

Block ID

Block and redirect actions now include a block_id in their action parameters. This same ID is also included in the generated event, allowing the WAF caller to reference it in the blocking response or add it as a query parameter in a redirect. This ensures that each blocking action can be reliably correlated with its corresponding event.

The following is an example of a block request action, including the new ID:

actions:
  block_request:
    status_code: 403
    grpc_status_code: 10
    type: auto
    block_id: "55af6314-9e02-11f0-b0a3-23dee2d4f390"

Identifier validation through checksums

A new operator, match_regex_with_checksum, has been introduced to improve the accuracy of detections performed using a regular expression, when the identifier itself has a built-in validation mechanism, by performing a secondary validation through a checksum. The checksum may be a purpose-built or generic algorithm, however at this time only the Luhn algorithm is supported.

The configuration of the operator is equivalent to the match_regex operator, except for the addition of the checksum parameter:

operator: match_regex_with_checksum
parameters:
  inputs: [{ address: server.request.body }]
  regex: "\\b4\\d{3}(?:(?:,\\d{4}){3}|(?:\\s\\d{4}){3}|(?:\\.\\d{4}){3}|(?:-\\d{4}){3})\\b"
  options: { min_length: 16 }
  checksum: luhn

Incremental processor overrides

Processor overrides have been updated to allow for incremental additions or removals of scanners to a given processor. Before this release, processor overrides fully replaced the list of scanners of a processor, however now each override contributes to the set by either adding or removing scanners.

While this is technically a breaking change, processor overrides are not currently in use. An example of a processor override including and excluding scanners can be seen below:

{
  "processor_overrides": [
    {
      "target": [{ "id": "extract-content" }],
      "scanners": {
        "include": [{ "id": "scanner-001" }],
        "exclude": [{ "tags": { "type": "email" } }]
      }
    }
  ]
}

Release changelog

Fixes

  • Fix single-char matches on phrase_match (#462)

Changes

  • match_regex_with_checksum operator: match and verify regexes with a checksum (#450)
  • Add block ID to block & redirect action parameters & event (#459)
  • Incremental processor overrides (#461)

Miscellaneous

  • Replace number with integer for integer-only attrs (#457)

v1.28.1 (unstable)

Choose a tag to compare

@github-actions github-actions released this 03 Sep 12:43
03f7484

Fixes

  • Support float status codes in configuration (#448)

v1.28.0 (unstable)

Choose a tag to compare

@github-actions github-actions released this 01 Sep 09:55
bbe9915

New Features

This release introduces a new URI-decomposition preprocessor along with enhancements to action parameter types, initialization performance, and platform support.

Since this release introduces breaking changes, a new section has been added to the upgrading guide.

URI parsing preprocessor

A new uri_parse preprocessor has been introduced to convert a single URI into a structured map. URI decomposition follows RFC 3986, with some additions from WHATWG for compatibility. This preprocessor improves the ability of the rule writer to target specific URI components without the need for crafting complex and innacurate regular expressions.

An example definition of this preprocessor can be seen below:

id: decompose-uri
generator: uri_parse
conditions: []
parameters:
  mappings:
    - inputs:
        - address: server.request.uri.raw
      output: server.request.uri
evaluate: true
output: false

After the evaluation of this example preprocessor server.request.uri will be available as a map containing the following fields:

{
  "scheme": <string>,
  "userinfo": <string>,
  "host": <string>,
  "port": <unsigned>,
  "path": <string>,
  "query": {},
  "fragment": <string>
}

Action parameters: broader scalar support

Action parameters can now include any of the available scalar types in addition to strings. This enables more natural configurations and prevents the need for ad‑hoc conversions by the WAF caller. This is a small, incremental improvement ahead of v2’s planned complex‑type support.

In addition to this change, the status_code field of the block_request and redirect_request actions, as well as the grpc_status_code field of the block_request action, are now being stored and interpreted as an unsigned integer, rather than a string.

Performance & Initialisation

Due to the static initialisation cost of tokenizer regular expressions, this is now deferred to the first ruleset instantiation. This avoids startup overhead and protects request latency from any one‑time initialization costs. No behavior changes are expected for existing rules.

Platforms & CI

Continuous integration now builds and tests libddwaf on Windows ARM64, leveraging the windows-11-arm runners, this is an external contribution from @Greenie0701.

Release changelog

Changes

  • URI parsing preprocessor (#439)
  • Support other scalar types on action parameters (#441)
  • Load tokenizer regexes on first ruleset instantiation (#446)

Miscellaneous

  • Add support for building and testing windows arm64 (#440)

v1.27.0 (unstable)

Choose a tag to compare

@github-actions github-actions released this 01 Aug 16:21
a37a7a2

New Features

This release of libddwaf includes several new features designed to enhance usability and configurability for both users and rule writers. The following sections provide detailed descriptions of each significant addition.

Note: This release contains no breaking changes.

Improved WAF Builder

Although not a direct feature, the WAF builder has been improved to support empty configurations or configurations without side-effects, such as configurations lacking compatible items.

SSRF Operator Configuration

New configuration settings have been introduced to provide enhanced control over the SSRF heuristic's sensitivity.

Heuristic Options:

  • authority-inspection (default: true):

    • When set to true, scans the authority component (RFC-3986::Authority) for injections.
    • If false, the authority is ignored unless enforce-policy-without-injection is enabled, in which case the authority is checked against denylists regardless of injection.
  • path-inspection (default: false):

    • When set to true, inspects the path (RFC-3986::Path) for injections.
    • If false, path injections are ignored.
  • query-inspection (default: false):

    • When set to true, inspects the query (RFC-3986::Query) for injections.
    • If false, query injections are ignored.
  • forbid-full-url-injection (default: false):

    • When set to true, injections involving a full URL are flagged as vulnerabilities.
    • If false, these injections are ignored.
  • enforce-policy-without-injection (default: false):

    • When enabled, policies are enforced irrespective of detected injections, ensuring schemes and hosts are validated against allowlists and denylists.
    • If false, the policy applies only upon detecting relevant injections.

Policy Options:

  • allowed-schemes: Array of allowed schemes (RFC-3986::Scheme), validated upon injection detection or when policy enforcement is active.
  • forbidden-domains: Array of forbidden domains (RFC-3986::Host), validated upon injection detection or when policy enforcement is active.
  • forbidden-ips: Array of forbidden IPv4/IPv6 addresses, evaluated similarly to forbidden-domains.

Example Configuration:

id: rasp-934-100
name: Server-side request forgery exploit
tags:
  type: ssrf
  module: rasp
conditions:
  - parameters:
      resource:
        - address: server.io.net.url
      params:
        - address: server.request.query
        # Additional parameters...
      options:
        authority-inspection: true
        path-inspection: false
        query-inspection: false
        forbid-full-url-injection: true
        enforce-policy-without-injection: false
      policy:
        allowed-schemes: []
        forbidden-domains: []
        forbidden-ips: []
    operator: ssrf_detector

Negated Operator Improvements

Negated operators (e.g. !match_regex) have been enhanced for greater clarity and functionality:

  • Negated operators now explicitly require the presence of the defined key path.
  • Evaluations must involve at least one compatible object type; for example, !match_regex matches only if evaluated data contains strings.
  • Non-matching values are now clearly reported when evaluating scalar or single-value arrays.

These improvements ensure more precise and predictable rule behavior.

JSON to Object Helper

A new helper function simplifies object creation from JSON strings:

bool ddwaf_object_from_json(ddwaf_object *output, const char *json_str, uint32_t length);
  • output: Pointer to the object populated with JSON content.
  • json_str: JSON data as a string.
  • length: Length of the JSON string.

The function returns a boolean indicating success (true) or failure (false). Both the input string and resulting object remain owned by the caller.

Release changelog

Changes

  • Add helper for object creation from JSON string (#430)
  • SSRF Operator Configuration (#434)
  • Negated operator fixes & improvements (#435)
  • Accept empty and inconsequential configurations (#437)

Miscellaneous

  • Fix typo in doc-string (#424)
  • Fix markdown typo in UPGRADING.md (#429)
  • Update linux builds and tests to use LLVM-19 (#431)
  • Use github-provided ubuntu arm64 runner (#433)

v1.26.0 (unstable)

Choose a tag to compare

@github-actions github-actions released this 02 Jul 10:43
75c1e92

New features

This release introduces a new operator, hidden_ascii_match, designed to detect hidden ASCII characters within arbitrary text inputs. Hidden ASCII refers specifically to characters found within the Unicode range [U+E0000, U+E007F]. This Unicode block was initially defined to provide non-printable mappings of standard ASCII characters, effectively allowing ASCII data to be embedded invisibly within text.

Hidden ASCII characters have been increasingly leveraged to inject concealed instructions into prompts provided to LLMs, manipulating their behavior without explicit visibility to users or systems. The introduction of the hidden_ascii_match operator represents the first step toward a deterministic AI security strategy, proactively identifying and flagging these character sequences to support the effective monitoring and mitigation of potential Unicode-based prompt injection exploits.

Release changelog

Changes

  • Hidden ASCII Matcher (#411)

Fixes

  • Add missing ddwaf_builder_get_config_paths export to windows shared libraries (#421)

Miscellaneous

  • Replace re2::StringPiece with std::string_view (#412)
  • Add artifact comparison to PR (#422)