vulnify
Runtime authorization for AI agents. Ask Vulnify whether an action is allowed before the agent runs it. Standard library only, Python 3.9+.
A check returns one of three decisions:
ALLOW— the action may run.REVIEW— a person must approve it.guard()does not run the action unless you passwaitand the review is approved.BLOCK— the action must not run.
The default is fail-closed (fail_mode="closed"). If Vulnify cannot be reached, the SDK returns BLOCK and sets degraded to True. Pass fail_mode="open" to allow the action in that case. Decision.degraded tells you when the fallback was used. Configuration errors (invalid API key, unknown agent or resource, invalid payload) always raise VulnifyError.
Optional content is scanned for sensitive data. The content is not stored. Matches come back as dlp_findings.
base_url defaults to http://localhost:3000. The production API is https://api.vulnify.io.
Install
pip install vulnify
Usage
import os
from vulnify import Vulnify, VulnifyBlockedError
vulnify = Vulnify(api_key=os.environ["VULNIFY_API_KEY"], base_url="https://api.vulnify.io")
# Runs export_customers() only if Vulnify says ALLOW. BLOCK raises VulnifyBlockedError.
# With wait={"timeout": 300}, a REVIEW decision waits for a person and runs only if approved.
vulnify.guard(
export_customers,
agent="SalesBot", action="EXPORT_DATA", resource="Customer Database",
destination="EXTERNAL_EMAIL", records_affected=12000,
wait={"timeout": 300},
)
@vulnify.protect(agent="SalesBot", action="EXPORT_DATA", resource="Customer Database")
def export_customers():
...
d = vulnify.check(agent="SalesBot", action="READ_DATA", resource="Customer Emails", content=email_body)
print(d.decision, d.risk_score, d.reasons, d.dlp_findings) # content is scanned, never stored
Network errors are retried with the same Idempotency-Key, so a retry does not create a duplicate event.
CrewAI and LangGraph
vulnify.adapters guards agent tools without importing either framework. Examples are in examples/.
from vulnify.adapters import guard_crewai_tool, crewai_before_tool_call, langgraph_tool_guard, alanggraph_tool_guard
def describe_export(args):
return {"agent": "SalesBot", "action": "EXPORT_DATA", "resource": "Customer Database", "records_affected": args["rows"]}
export_tool = guard_crewai_tool(vulnify, ExportCustomers(), describe_export)
hook = crewai_before_tool_call(vulnify, {"export_customers": describe_export})
node = ToolNode(tools, wrap_tool_call=langgraph_tool_guard(vulnify, {"export_customers": describe_export}))
A blocked call does not run the tool. The CrewAI tool answers the reason to the agent (on_blocked="raise" raises instead), the hook returns False, and LangGraph gets an error ToolMessage. Pass wait={"timeout": 120} to wait for a person on REVIEW. Tools missing from the mapping run unchanged.
Development
pip install -e ".[dev]"
pytest
License
MIT. Copyright 2026 Vulnify.
Metadata
Release files for vulnify 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vulnify-0.1.0.tar.gz | 8.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vulnify-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.6 kB
Release files / vulnify-0.1.0.tar.gz
| Download URL | vulnify-0.1.0.tar.gz |
|---|---|
| Size | 8.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9586a2b5ad25e86fa02575aa8bd3d468e45b41be1ae247eb2f5be4fc49cf9928
|
|
BLAKE2b-256 checksum How to use checksums |
5e10c69120d07ba052751cb52ee8e003147b8265023a33997859ff7a0d5bca40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|
Release files / vulnify-0.1.0-py3-none-any.whl
| Download URL | vulnify-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a829805ec40d9d6576cb14aa9ee965fefb94621360f0f79e39d916d0e4ef1e84
|
|
BLAKE2b-256 checksum How to use checksums |
00f21189e5cd33b87c51ca5b77f93c0256b77bd015d7a648d2ccd0f680e2641a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.3
|