Repository navigation
Description
Affected versions / environment
CyberStrikeAI v1.7.24 (commit 4ca8b7d33663cd4ba8213f4afa8194ae1928ef16), and the same decision code remains on the default branch. The deployment must enable HITL approval with default_reviewer: audit_agent and audit_backend: typesafe.
Summary
An HTTP 200 response from the TypeSafe audit backend with an empty or partial answers object is accepted as a successful evaluation. The client turns nil/missing answers into an empty map, the decision code reads the absent answers as zero, and the audit agent applies its default “approve”. The HITL middleware then runs the tool, and the approval record attributes the decision to the audit agent. A provider incident, a truncated response, or a malformed 200 body is enough to run a tool that was supposed to be gated.
A complete destructive answer (availability.noul = 0.97) and an HTTP 500 both reject correctly; the empty/partial 200 path is the one that approves.
Details / root cause
internal/typesafe/client.go(SystemOne) only checks the HTTP status and JSON decoding. Nilanswersis normalized to an empty map;Noulreturns 0 for missing, nil or non-numeric answers.internal/hitl/jev.go(DecideJev) treats the absent evaluation as “no destructive signal” and follows its “uncertain → approve” default. It distinguishesresult == nil, but not “HTTP 200 with no usable answers”.internal/handler/hitl_audit_agent.gopasses the result toDecideJev; the HITL middleware then proceeds and executes the tool.
Reproduction
Control (complete destructive answer):
- Enable HITL approval with
default_reviewer: audit_agentandaudit_backend: typesafe. - Point the TypeSafe endpoint at a test server returning a complete destructive answer set.
- Trigger an
exectool call through the normal conversation/approval flow. The audit agent rejects, the tool does not run, and no marker is created.
Fault (empty or partial answer):
- Same setup, but TypeSafe returns HTTP 200 with
{"answers":{}}, or only one answer key. - Trigger the same
execcall. - Baseline: the audit agent approves, the tool executes, and the command output/marker is observable.
- Expected after fix: the audit agent rejects the incomplete evaluation and the tool does not execute.
Expected behavior
An empty or incomplete audit response means the evaluation did not complete, so it must be rejected or retried, never treated as “no destructive signal”.
Actual behavior
The tool executes while the deployment believes the audit agent approved it; the only changed variable is the TypeSafe response body.
Impact
Any HITL-gated tool can run during a TypeSafe incident or with a malformed 200 response, including the exec tool. The operator gets no error, retry, or conservative rejection, and the approval record makes the failure look legitimate.
Affected deployments
Deployments with HITL approval enabled, default_reviewer: audit_agent, and audit_backend: typesafe. HITL is off by default, so stock deployments without HITL are not affected; tools in hitl.tool_whitelist are exempt by configuration.
Suggested fix
Validate that every requested audit question has a usable typed answer before applying DecideJev; treat an empty/partial result as an evaluation failure (reject/retry), not as a low-risk result. Preserve the complete destructive and HTTP-error rejection paths.
Fix
A fix is open in #394: SystemOne rejects empty/partial/malformed answer sets, and DecideJev re-validates the built-in questions so a directly constructed incomplete result also rejects. The existing destructive, HTTP-error and HITL-off paths are unchanged.
Activity
[-]HITL audit: empty TypeSafe response is treated as approval and executes tools[/-][+][Security] HITL audit: empty TypeSafe response is treated as approval and executes tools[/+]