This repository is a reference implementation for the CSAF standard in Rust that relies on automatically generating CSAF document structs from the JSON schema.
This is work-in-progress.
csaf-validatorcontains a command line tool to validate CSAF documents.csaf-rscontains the actual validator library which currently publishes a crate to crates.io.csaf-fficontains UniFFI bindings that exposecsaf-rsto other languages (Go, WASM/TypeScript, and more).go/contains generated Go bindings and integration tests.wasm/contains generated WASM/TypeScript bindings and integration tests.
1.88.0
After building or downloading csaf-validator from the available releases, the usage is quite simple and additional help can be display using --help.
A validator for CSAF documents
Usage: csaf-validator [OPTIONS] <PATH>
Arguments:
<PATH>
Options:
-c, --csaf-version <CSAF_VERSION> Version of CSAF to use [default: 2.0]
-p, --preset <PRESET> The validation preset to use [default: basic]
-t, --test-id <TEST_ID> Run only the selected tests, may be specified multiple times
-h, --help Print help
-V, --version Print version
Some examples to use are included below. Please note that the validation is not yet fully implemented!
# validate a CSAF 2.0 document with profile basic (the default)
csaf-validator --csaf-version 2.0 my-csaf-2-0-document.json
# validate a CSAF 2.0 document with profile full
csaf-validator --csaf-version 2.0 --preset full my-csaf-2-0-document.json
# validate a CSAF 2.1 document with one specific test
csaf-validator --csaf-version 2.1 --test-id 6.1.34 my-csaf-2-1-document.jsonYou can also use the library version as depicted here:
use csaf::csaf2_0::loader::load_document;
use csaf::schema::csaf2_0::schema::CommonSecurityAdvisoryFramework;
use csaf::validation::{Validatable, validate_by_preset, validate_by_test, validate_by_tests};
let csaf_version = "2.0";
let path = "/path/to/local/cve-2025-9820.json";
// validate a preset
let preset_results = validate_by_preset(&document, csaf_version, "basic");
// validate multiple tests
let multiple_tests_result = validate_by_tests(&document, csaf_version, &["6.1.1", "6.1.10", "6.1.20"]);
// validate a single test
let single_test_result = validate_by_test(&document, "6.1.13");
// get all test ids from a preset
let test_ids_in_basic_preset = CommonSecurityAdvisoryFramework::tests_in_preset("basic");To use this library you have to download the binaries for your specific operating system and platform. A download script is provided to help you with that.
You can either install systemwide (sudo may be needed)
go run github.com/csaf-rs/csaf/go/cmd/download-libs --system
go build ./...Or without root permissions, but you have to tell the linker where to find the artifacts:
go run github.com/csaf-rs/csaf/go/cmd/download-libs # one-time, writes to ~/.cache/csaf-ffi/
CGO_LDFLAGS="-L$HOME/.cache/csaf-ffi/lib/$(go env GOOS)_$(go env GOARCH)" go build ./...Alternatively you can put the CGO_LDFLAGS export in your shell profile.
Then add it to your project with
go get github.com/csaf-rs/csaf/goor directly to your go.mod file with
require github.com/csaf-rs/csaf/goYou can then import the necessary package into your code like this
import (
"github.com/csaf-rs/csaf/go/csaf_ffi"
)The easiest way to validate a document is to use the generic ValidateCsaf function, which takes the document and a preset to test against.
result, err := csaf_ffi.ValidateCsaf(string(data), preset)If you want to build csaf-validator on your own, please install Rust (see https://rustup.rs) and then run
# make sure submodules are up-to-date
git submodule init
git submodule update --remote
# make sure that local assets are in sync with git submodules
./update_assets.sh
# run the tests
cargo test
# build for release
cargo build --releaseThe final binary will be in target/release and can then be installed, for example, in a system-wide folder.
Bindings for other languages are created through the csaf-ffi crate, which is built by the language specific generate_XXX_bindings script.
The Go bindings are generated via uniffi-bindgen-go.
# Install the Go binding generator (one-time)
cargo install uniffi-bindgen-go \
--git https://github.com/NordSecurity/uniffi-bindgen-go \
--tag v0.7.0+v0.31.0
# Build the Rust library, generate bindings, and copy the static archive
./generate_go_bindings.shThis creates GO code in the go/csaf_ffi folder.
To run the Go tests:
cd go
go test -v ./csaf_ffi/As a demonstration there is a small CLI and Webserver example included.
cd go
CGO_LDFLAGS="-L$HOME/.cache/csaf_ffi/lib/$(go env GOOS)_$(go env GOARCH)" go run -buildvcs=false ./cmd/example/ <PATH_TO_CSAF_FILE>cd go
CGO_LDFLAGS="-L$HOME/.cache/csaf_ffi/lib/$(go env GOOS)_$(go env GOARCH)" go run -buildvcs=false ./cmd/webapi/The server listens on port 8080 by default. Set the PORT environment variable
to use a different port:
PORT=9090 go run -buildvcs=false ./cmd/webapi/Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/api/validate/json |
Validate a CSAF document sent as a raw JSON body |
POST |
/api/validate/upload |
Validate a CSAF document sent as a multipart file upload (field: file) |
Both endpoints accept the optional query parameter ?preset=basic (default),
?preset=extended, or ?preset=full.
Example:
curl -X POST http://localhost:8080/api/validate/json?preset=basic \
-H 'Content-Type: application/json' \
--data-binary @my-csaf.jsonThe WASM bindings are generated via uniffi-bindgen-js.
# Install the WASM binding generator (one-time)
cargo install uniffi-bindgen-js --version 0.2.1
# Build and generate (uses generate_wasm_bindings.sh)
./generate_wasm_bindings.shThis creates TypeScript + WASM output in wasm/.
- ✅ Implemented
- ⭕ Not applicable
| Test specification | 2.0 | 2.1 (experimental) |
|---|---|---|
| 6.1.1 | ✅ | ✅ |
| 6.1.2 | ✅ | ✅ |
| 6.1.3 | ✅ | ✅ |
| 6.1.4 | ✅ | ✅ |
| 6.1.5 | ✅ | ✅ |
| 6.1.6 | ✅ | ✅ |
| 6.1.7 | ✅ | |
| 6.1.8 | ✅ | |
| 6.1.9 | ✅ | ✅ |
| 6.1.10 | ✅ | ✅ |
| 6.1.11 | ✅ | |
| 6.1.12 | ✅ | ✅ |
| 6.1.13 | ✅ | ✅ |
| 6.1.14 | ✅ | |
| 6.1.15 | ✅ | ✅ |
| 6.1.16 | ✅ | ✅ |
| 6.1.17 | ✅ | ✅ |
| 6.1.18 | ✅ | ✅ |
| 6.1.19 | ✅ | ✅ |
| 6.1.20 | ✅ | ✅ |
| 6.1.21 | ✅ | ✅ |
| 6.1.22 | ✅ | ✅ |
| 6.1.23 | ✅ | ✅ |
| 6.1.24 | ✅ | ✅ |
| 6.1.25 | ✅ | ✅ |
| 6.1.26 | ✅ | ✅ |
| 6.1.27.1 | ✅ | ✅ |
| 6.1.27.2 | ✅ | ✅ |
| 6.1.27.3 | ✅ | ✅ |
| 6.1.27.4 | ✅ | ✅ |
| 6.1.27.5 | ✅ | ✅ |
| 6.1.27.6 | ✅ | ✅ |
| 6.1.27.7 | ✅ | ✅ |
| 6.1.27.8 | ✅ | ✅ |
| 6.1.27.9 | ✅ | ✅ |
| 6.1.27.10 | ✅ | ✅ |
| 6.1.27.11 | ✅ | ✅ |
| 6.1.27.12 | ⭕ | ✅ |
| 6.1.27.13 | ⭕ | |
| 6.1.27.14 | ⭕ | ✅ |
| 6.1.27.15 | ⭕ | ✅ |
| 6.1.27.16 | ⭕ | ✅ |
| 6.1.27.17 | ⭕ | ✅ |
| 6.1.27.18 | ⭕ | ✅ |
| 6.1.27.19 | ⭕ | ✅ |
| 6.1.28 | ✅ | ✅ |
| 6.1.29 | ✅ | ✅ |
| 6.1.30 | ✅ | ✅ |
| 6.1.31 | ✅ | ✅ |
| 6.1.32 | ✅ | ✅ |
| 6.1.33 | ✅ | |
| 6.1.34 | ⭕ | ✅ |
| 6.1.35 | ⭕ | ✅ |
| 6.1.36 | ⭕ | |
| 6.1.37 | ⭕ | |
| 6.1.38 | ⭕ | ✅ |
| 6.1.39 | ⭕ | ✅ |
| 6.1.40 | ⭕ | ✅ |
| 6.1.41 | ⭕ | ✅ |
| 6.1.42 | ⭕ | ✅ |
| 6.1.43 | ⭕ | ✅ |
| 6.1.44 | ⭕ | ✅ |
| 6.1.45 | ⭕ | |
| 6.1.46 | ⭕ | ✅ |
| 6.1.47 | ⭕ | ✅ |
| 6.1.48 | ⭕ | |
| 6.1.49 | ⭕ | |
| 6.1.50 | ⭕ | |
| 6.1.51 | ⭕ | |
| 6.1.52 | ⭕ | |
| 6.1.53 | ⭕ | ✅ |
| 6.1.54 | ⭕ | ✅ |
| 6.1.55 | ⭕ | ✅ |
| 6.1.56 | ⭕ | ✅ |
| 6.1.57 | ⭕ | ✅ |
| 6.1.58 | ⭕ | ✅ |
| 6.1.59 | ⭕ | |
| 6.1.60.1 | ⭕ | |
| 6.1.60.2 | ⭕ | |
| 6.1.60.3 | ⭕ | |
| 6.1.61 | ⭕ | ✅ |
| Test specification | 2.0 | 2.1 (experimental) |
|---|---|---|
| 6.2.1 |
| Test specification | 2.0 | 2.1 (experimental) |
|---|---|---|
| 6.3.1 |