mulval

module
v0.0.0-...-c35cfa1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: Apache-2.0

README ΒΆ

MulVAL (as a Service)

Attack graph generation over gRPC, backed by first-order Datalog inference

License Go reference
CI Docker pulls

MulVAL (as a Service) wraps MulVAL β€” a logic-based network security analyser β€” behind a gRPC/REST API to distribute its capabilities to third-party services. Clients submit EDB facts and optional IDB interaction rules; the service runs MulVAL in the background and returns a Long-Running Operation (LRO) that resolves to the generated attack graph.

[!NOTE] This project is research-grade software. Changes can happen at any time in a non-backward-compatible way.

πŸš€ What MulVal (as a Service) Does

  • Simplify MulVal usage β€” Running MulVal can become quite complex depending on your infrastructure, so running it as a Service helps bootstrapping it fast to experiment;
  • Manages multi-experiments β€” Every analysis is stored so can be shared among researchers and engineers in a lab, or used to iterate;
  • Reusability β€” Designed as a microservice, MulVal (as a Service) provides a gRPC/HTTP REST API that can be used by third-party services to run their experiment;
  • Visualization β€” Provide a UI that maps the API features for running in-browser experiments and visualize the results.

🧩 Architecture

The service is stateless between requests; all durable state lives in PostgreSQL. NATS JetStream is used only for completion notifications β€” WaitOperation subscribes to a per-operation subject and blocks until the executor publishes a state change, avoiding poll loops. If NATS is unavailable the service degrades gracefully: WaitOperation returns after its timeout with done=false.

⚑ Quick start

# Write the configuration file config.yaml
# An example:
#
# logLevel: info
# events:
#   url: nats://localhost:4222
#   instanceID:
#     from_env: HOSTNAME
# storage:
#   dsn: postgres://user:secret@localhost:5432/mulval-backend
#   schema: mulval
#   migrate: true
#   minConns: 4

# Start the MulVal (as a Service) Docker container.
# Add --ui for the web graphical interface.
docker run -p 8080:8080 -v config.yaml:/config.yaml cvewatcher/mulval:latest --config=/config.yaml --ui

# The service is now available at localhost:8080 (gRPC/HTTP REST)
# The web UI is at http://localhost:8080/ui/

Submitting an analysis via curl

curl -s -X POST http://localhost:8080/api/v1/analyses \
  -H 'Content-Type: application/json' \
  -d '{
    "edbFacts": [
      "attackerLocated(internet).",
      "attackGoal(execCode(fileServer,_)).",
      "hacl(internet, webServer, tcp, 80).",
      "hacl(webServer, fileServer, tcp, 445).",
      "hacl(H, H, _, _).",
      "networkServiceInfo(webServer, httpd, tcp, 80, apache).",
      "vulExists(webServer, '\''CVE-2021-44228'\'', httpd).",
      "vulProperty('\''CVE-2021-44228'\'', remoteExploit, privEscalation).",
      "networkServiceInfo(fileServer, smb, tcp, 445, root).",
      "vulExists(fileServer, '\''CVE-2017-0144'\'', smb).",
      "vulProperty('\''CVE-2017-0144'\'', remoteExploit, privEscalation)."
    ]
  }'

This returns an LRO immediately:

{
  "name": "operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "done": false
}

Poll until complete:

curl -s -X POST http://localhost:8080/api/v1/operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:wait \
  -H 'Content-Type: application/json' \
  -d '{"timeout": "30s"}'

When done: true, the response contains the full Analysis resource including verticesCsv, arcsCsv, and the parsed graph.

πŸ–ΌοΈ User Interface

All analyses MulVal (as a Service) ran. The details of an analysis, with a graph display of the results. The creation form.
CaptureDetail

πŸ”¨ Development setup

OpenTelemetry

  • Setup:
    export OTEL_EXPORTER_OTLP_ENDPOINT=dns://localhost:4317
    export OTEL_EXPORTER_OTLP_INSECURE=true
    export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
    

PostgreSQL

  • Setup:

    docker run -d \
        --name postgres \
        -e POSTGRES_DB=mulval-backend \
        -e POSTGRES_USER=user \
        -e POSTGRES_PASSWORD=secret \
        -p 5432:5432 \
        postgres:16-alpine
    
  • Teardown:

    docker rm -f postgres
    
  • Adminer, for debug purposes:

    docker run -p 8082:8080 adminer
    

    You can connect with:

    • System: PostgreSQL
    • Server: The result of echo "$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' postgres):5432"
    • Username: user
    • Password: secret
    • Database: mulval-backend

NATS JetStream

  • Setup:

    docker run -d \
        --name nats-js \
        -p 4222:4222 \
        -p 8222:8222 \
        nats:latest -js -m 8222
    
  • Teardown:

    docker rm -f nats-js
    

Directories ΒΆ

Path Synopsis
api
v1
cmd
mulval command
deploy module
pkg
store
Package store provides the persistence layer for MulVAL analyses.
Package store provides the persistence layer for MulVAL analyses.
ui
proto
api/v1/analysis
Package analysis is a reverse proxy.
Package analysis is a reverse proxy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL