Kelvar Docs

Reference

API reference

When you start the service with --api-port, it answers on a small local HTTP API. Responses are JSON. The API reports the state of the most recent tick, serves the journal, and accepts webhook events.

sh
curl http://127.0.0.1:8787/status

#Base URL

http://<api-host>:<api-port>, where --api-host defaults to 127.0.0.1. The API is off until you set --api-port.

#GET /status

Returns counts from the last tick and whether it blocked. It is empty until the first tick finishes.

json
{
  "blocked": true,
  "insights": 2,
  "findings": 3,
  "actions": 1,
  "t": 1793000000.123
}
FieldMeaning
blockedtrue if any action in the tick was a block.
insightsNumber of connector insights in the tick.
findingsNumber of scanner findings in the tick.
actionsNumber of actions the policy chose.
tUnix time when the tick finished.

#GET /findings

Returns the scanner findings from the last tick.

json
[
  {
    "check": "zero_click",
    "severity": "critical",
    "path": "webhook_handler.py",
    "line": 4,
    "message": "unsafe deserialization sink (zero-click RCE vector)"
  }
]

#GET /insights

Returns the insights from the last tick, plus any received through webhooks since then.

json
[
  {
    "connector": "siem-alerts",
    "kind": "alert",
    "title": "Impossible travel for a service account",
    "severity": "high",
    "source_id": "a-4821",
    "observed_at": 1793000000.1,
    "detail": {}
  }
]

#GET /journal

Returns the last rows of the journal. Use n to choose how many. The default is 100.

sh
curl "http://127.0.0.1:8787/journal?n=20"

Each row has a kind of tick, finding, insight, action or kernel-error, and a t timestamp.

#POST /webhook/{source}

Sends an event for inspection. The body is JSON. Kelvar scans the raw body for zero-click sinks and for the same secret patterns that the secrets check uses. If either matches, the severity is set to the matched rule's severity. Otherwise it uses severity from the payload, or info.

sh
curl -X POST http://127.0.0.1:8787/webhook/okta \
  -H "Content-Type: application/json" \
  -d '{"event": "user.session.start", "severity": "low"}'

The response says whether Kelvar blocked the event. A severity of high or critical means block, and anything lower means pass.

json
{
  "ok": true,
  "verdict": "pass",
  "insight": {
    "connector": "webhook:okta",
    "kind": "signal",
    "title": "user.session.start",
    "severity": "low",
    "source_id": "wh-1793000000123",
    "observed_at": 1793000000.123,
    "detail": { "verdict": "pass", "matched_rule": null, "payload": {} }
  }
}
FieldMeaning
verdictblock or pass.
insight.detail.matched_ruleThe rule that matched, or null.
insight.titleThe payload's title or event. A match replaces it with a description of the block.

Every webhook is appended to the journal as an insight, and a block is appended as an action as well.

#Errors

An unknown path returns status 404 with {"error": "not found"}. A request body that is not valid JSON is wrapped as {"raw": "<body>"} and still inspected.