Skip to content

Verify findings before you act on them

A Tulip Evidence is a claim. Before you act on it, verify() puts it through an independent skeptic that challenges the evidence and scores confidence. A well-grounded finding survives; an unsupported one is refuted, with the objections listed. verify() only returns the verdict: gate the action on survives so a refuted finding never reaches it. The default skeptic grades the evidence a finding carries; it does not check that the references are real.

verify() takes a Tulip Evidence or a finding-shaped dict (title, severity, gsar_score, evidence_refs, confidence), so a finding produced outside Tulip goes through the same challenge. The notebook verifies a real grounded finding (survives), a fabricated one with no evidence (refuted), and an external finding that has references but was never grounded (refuted).

Runs fully offline.

Run it: python examples/notebook_78_verify_findings.py

See also: Agentic AI-security · SecurityContext.

Source

#!/usr/bin/env python3
# Copyright 2026 The Tulip Authors
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

import asyncio

from tulip_security import Target, is_finding, red_team, verify


def _vulnerable_bot(prompt: str) -> str:
    return prompt  # naive bot: obeys injected instructions (see notebook 76)


def _show(label: str, verdict: object) -> None:
    v = verdict  # VerificationResult
    status = "SURVIVES" if v.survives else "REFUTED"  # type: ignore[attr-defined]
    print(f"\n[{status}] {label}  (confidence {v.confidence:.2f})")  # type: ignore[attr-defined]
    for r in v.refutations:  # type: ignore[attr-defined]
        print(f"    - ({r.weight}) {r.reason}")


async def main() -> int:
    print("verify() — does the evidence actually support the claim?")

    # 1. A REAL finding from red-teaming a vulnerable bot — well grounded.
    report = await red_team(Target.from_callable(_vulnerable_bot, name="bot"), suite="owasp-asi")
    real_finding = next(r for r in report if is_finding(r))
    _show(f"real finding: {real_finding.title}", await verify(real_finding))

    # 2. A FABRICATED finding from some other agent — no evidence at all.
    hallucination = {"title": "Host 10.0.0.5 is compromised", "severity": "critical"}
    _show("hallucinated finding (no evidence)", await verify(hallucination))

    # 3. An external finding that has refs but was never grounded.
    ungrounded = {
        "title": "Possible data exfiltration",
        "severity": "high",
        "evidence_refs": ["siem:alert:9931"],
    }
    _show("external finding (ungrounded)", await verify(ungrounded))

    return 0


if __name__ == "__main__":
    raise SystemExit(asyncio.run(main()))