Find what your AI agents can do that they shouldn't — before attackers do.
Project description
Lucin
Find what your AI agents can do that they shouldn't — before attackers do.
Lucin is an open-source static security scanner for AI agents. It reads the actual code inside your agent's tools — not just tool names or descriptions — and finds dangerous capability configurations before they reach production, mapped to the OWASP Top 10 for Agentic Applications.
Quick Start
pip install lucin
lucin scan ./my-agent/
No API keys. No configuration files. No account signup.
What It Does
| Command | Purpose | Status |
|---|---|---|
lucin scan |
Find security issues in agent tool code | ✅ Stable |
lucin info |
Show agent inventory without running detections | ✅ Stable |
lucin explain |
Explain a finding in depth (meaning, impact, fix) | ✅ Stable |
lucin fix |
Generate code fixes for findings | ✅ Stable |
lucin badge |
Security badge SVG for your README | ✅ Stable |
lucin discover |
Discover MCP configs across IDEs on this system | ✅ Stable |
lucin redteam |
Adversarial payload testing | 🧪 Experimental |
lucin monitor |
Behavioral deviation scoring on agent traces | 🧪 Experimental |
lucin serve |
REST API | 🧪 Experimental |
What It Finds
Lucin ships 29 detector modules (source: src/lucin/detectors/). 27 are
registered/active (from lucin.detectors import ACTIVE_DETECTOR_COUNT); two are
intentionally held back:
- AG-013 (memory poisoning) returns no findings — disabled pending real false-positive data (see note below).
- AG-PATH-TRAVERSAL is built, sound, and unit-tested but intentionally unregistered:
the benign corpus contains byte-identical legitimate file tools (
open(param),os.path.join(base, name)), so registering it would break the published 0-false-positive result (see Validated Capabilities). Precision over recall, by design (src/lucin/detectors/__init__.pydocuments the gate).
Rule IDs and severities below are read directly from the detector source (grep -rhoE 'id="AG-[A-Z0-9-]+"' src/lucin/detectors/*.py).
Scan scope: all file walks (parsers and the binary-payload check) skip vendored, build,
and VCS directories — venv/.venv, node_modules, site-packages, *.dist-info, .git,
dist, build, __pycache__ (src/lucin/_fs.py). This is what lets lucin scan .
run cleanly on a real checkout instead of flagging every compiled .so in your virtualenv.
| Rule ID | Finding | Severity |
|---|---|---|
| AG-001 | Unrestricted Shell/Exec Access | CRITICAL |
| AG-002 | Data Exfiltration Path (read → send chain) | HIGH–CRITICAL |
| AG-003 / AG-012 / AG-MCP-TOKENLEAK | Unauthenticated MCP · Unencrypted MCP Transport · MCP Token Leakage | HIGH / MEDIUM |
| AG-005 | Dangerous Tool Combinations | HIGH |
| AG-006 | No Human Approval for Destructive Actions | HIGH |
| AG-007 | Hardcoded / High-Entropy Secrets (pattern + Shannon entropy) | HIGH |
| AG-009 | Unlimited Sub-Agent Spawning | MEDIUM |
| AG-010 | No Rate Limiting on High-Risk Tools | MEDIUM |
| AG-011 | Tool Description Injection (tool poisoning) | HIGH |
| AG-013 | Memory/RAG Poisoning Risk | HIGH — disabled: detector returns no findings, rebuilding with real FP data |
| AG-014 | Multi-Agent Delegation Chain Risks (cross-agent) | HIGH |
| AG-015 | Supply Chain: Unpinned MCP Server | HIGH |
| AG-016 | Coding Agent Scope Violation | HIGH |
| AG-017 | Browser Agent Credential Access | CRITICAL |
| AG-019 | Context Window Overflow Risk | MEDIUM |
| AG-021 | Encoding/Obfuscation Detection (Base64/hex/zero-width) | HIGH |
| AG-023 | Agent Self-Modification Capability | HIGH |
| AG-024 | Cross-Origin MCP Escalation | HIGH |
| AG-025 | Tool Shadowing / Name Collision | MEDIUM |
| AG-026 | Ambient Authority (code exec without isolation / privileged Docker) | HIGH–CRITICAL |
| AG-027 | System-Prompt / Instruction Leakage | up to CRITICAL |
| AG-028 | Execution Without Telemetry/Monitoring | HIGH |
| AG-TRIFECTA | Lethal Trifecta (untrusted input + secret access + egress) | CRITICAL |
| AG-SQL | SQL / CQL Injection via Tainted Query | CRITICAL |
| AG-SSRF | Server-Side Request Forgery (tainted URL host → request sink) | HIGH — conservative: fires only when taint forms the URL host |
| AG-DESERIALIZE | Insecure Deserialization of untrusted-influenced bytes (CWE-502) | CRITICAL |
| AG-PATH-TRAVERSAL | Tool-controlled path → file sink without containment | HIGH — built + unit-tested but UNREGISTERED (precision: benign corpus has byte-identical legit file tools) |
| AG-DOCKER-EXEC | Unsafe Docker Exec / Container Escape | HIGH–CRITICAL |
| AG-RAG-NO-SANITIZE | RAG Retrieval Without Sanitization | HIGH |
| AG-CORS / AG-NOAUTH | Agent HTTP Server: Wildcard CORS · No Authentication | HIGH–CRITICAL |
| AG-ENV-FALLBACK | Insecure Secret Env Fallback | MEDIUM |
| AG-COMP | Compositional Capability Risk | HIGH |
| AG-FRAMEWORK-PIN | Unpinned Agent Framework Version | MEDIUM |
What it doesn't catch (honesty matters)
Lucin is a static pre-deploy scanner. It finds enabling misconfigurations and known dangerous patterns in code before you ship. It does not:
- Detect novel zero-days or emergent runtime behavior — these require runtime monitoring (not yet available in stable form).
- Catch vulnerabilities that only appear during execution — dynamic injection, runtime prompt attacks, or behavior that emerges from model+tool interaction.
- Guarantee 100% detection — coverage depends on how the agent is structured. Highly dynamic Python (heavy
getattr, reflection, generated code) reduces recall. - Solve alignment — we bound what tools can do; we don't fix the model's intent.
Interprocedural / cross-file taint (known limitation)
Lucin does not perform whole-program, call-graph-based interprocedural taint analysis. The standard tool for building that call graph in Python — PyCG — is currently unavailable on our build mirror, so it is not vendored or integrated.
What the scanner actually does today:
- Single-function (intraprocedural) taint, flow-sensitive and field-insensitive,
over each tool/function body (
src/lucin/parsers/body_inspector.py,intraproc_taint). This is what runs in production scans. - Capability-based classification as the cross-function approximation: instead of proving a data-flow path from an untrusted source in function A to a sink in function B, we classify each tool by the capabilities its code exhibits (reads untrusted input, executes shell, performs network egress, touches secrets, …) and flag dangerous combinations on an agent/tool (e.g. the lethal-trifecta and dangerous-combination detectors). This catches the incident-class patterns without a precise inter-function path.
- Limited cross-function / intra-class taint (
src/lucin/analysis/cross_function_taint.py) is wired into the SSRF, insecure-deserialization and path-traversal detectors (viadetectors/_taint.py). It resolves same-file method-to-method flows — e.g. a value stored in__init__and later reaching apickle.loadsink — but it is not a whole-program call graph and does not cross files or resolve dynamic dispatch. - A separate summary-based analyzer (
src/lucin/analysis/file_scope_taint.py) exists and is unit-tested but is not wired into the production scan path — experimental, not shipping coverage.
What this means for recall (stated honestly):
- Vulnerabilities where an untrusted value enters in one function and reaches a sink in a
different function or a different file, and where no single tool exhibits the
dangerous capability combination on its own, may be missed by precise data-flow
reasoning. The capability-combination heuristic recovers many of these but not with
path-level precision, and it does not resolve dynamic dispatch (
getattr, reflection), which is treated as a conservative barrier. - Recall is measured and partial — 76%. On a held-out corpus of 50 distinct
vulnerable agents across 10 vuln classes (22 real third-party cases + 28 clearly
labeled constructed cases), Lucin's measured recall is 38/50 = 76%
(24% false-negative rate; 19/22 = 86% on the real third-party cases alone) —
python benchmarks/recall_corpus.py(offline-reproducible; provenance per case inbenchmarks/recall_corpus/manifest.json). Per-class recall: 100% on SQL/CQL injection, command injection, eval/exec RCE, CORS/no-auth servers, the lethal trifecta, and insecure deserialization (AG-DESERIALIZE + cross-function taint); 80% container-escape (AG-DOCKER-EXEC); 17% SSRF (AG-SSRF is deliberately conservative — it fires only when taint forms the URL host, trading recall for the published 0-false-positive precision); and 0% path traversal (AG-PATH-TRAVERSAL is built and sound but unregistered — see the detector note above). We publish the misses as-is rather than claim coverage we do not have (the false-negative list is printed by the benchmark).
A clean scan means no known dangerous patterns were found in static configuration. It doesn't mean the agent is safe under all inputs.
Supported Frameworks
- LangChain / LangGraph — AST-based Python source analysis
- MCP — JSON/YAML config scanning
- CrewAI — YAML + Python with 20+ builtin tool mappings
- AutoGen — Python-based (AssistantAgent, UserProxyAgent)
- OpenAI Swarm — Python-based agent/handoff analysis
- PydanticAI — Python-based agent + tool analysis
- Google ADK — Python-based agent analysis
- OpenAI Assistants — JSON config (code_interpreter, functions), handled by the generic parser
- Any Python agent — Generic parser catches @tool decorators + schemas
Usage
# Scan agent code
lucin scan ./my-agent/
# Scan with CI mode (exit code 1 on critical/high findings)
lucin scan ./my-agent/ --ci --fail-on high
# Red team with targeted attacks (informed by agent's actual tools)
lucin redteam ./my-agent/
# Red team with multi-turn conversational attacks
lucin redteam ./my-agent/ --multi-turn
# Monitor agent behavior for anomalies (ML-based)
lucin monitor ./traces.jsonl
# Generate code fixes
lucin fix ./my-agent/ --id AG-007
# Generate OCSF output for SIEM integration
lucin scan ./my-agent/ --format ocsf
# Generate security badge
lucin badge ./my-agent/ --style score
# Start API server
lucin serve --port 8080
Security Score
Every scan produces a 0-100 security score:
| Score | Rating | Meaning |
|---|---|---|
| 90-100 | Excellent | No critical/high findings |
| 70-89 | Good | Minor issues only |
| 50-69 | Concerning | Significant gaps |
| 25-49 | Poor | Serious vulnerabilities |
| 0-24 | Critical | Immediate action required |
How It Works
Your Agent Code / MCP Config
│
▼
┌─────────────────────┐
│ Framework Parsers │ 8 parsers (LangChain, MCP, CrewAI, AutoGen, Swarm,
│ → Normalized Model │ PydanticAI, Google ADK, Generic — OpenAI Assistants via Generic)
└─────────┬───────────┘ Schema-based capability classification
│
▼
┌─────────────────────┐
│ Detection Engine │ 29 detector modules (27 active), OWASP-mapped
│ → De-obfuscation │ Decode Base64/hex/zero-width before detection
│ → Data Flow │ Single-function taint + capability-combination analysis
│ → Supply Chain │ MCP server integrity verification
│ → ML Scoring │ 5-model behavioral ensemble
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Output │ Terminal / JSON / HTML / OCSF (SIEM)
│ → Security Score │ 0-100 calibrated score
│ → Fix Generation │ 8 contextual code fix types
│ → Badge │ SVG for README
└─────────────────────┘
Validated Capabilities (reproducible)
Every number below ships with the command that regenerates it. Numbers on synthetic corpora are labeled as such; capabilities that genuinely require real users/traces are labeled not-yet-validated (launch-gated) and are not claimed as done.
Test suite: 517 passing (12 skipped, 1 xfail) — python -m pytest tests/ -q.
| Capability | Measured result | Regenerate with | Status |
|---|---|---|---|
| SCAN precision (benign corpus) | 0 confirmed false positives across 52 real repos / 2,732 files — counted per distinct (file, detector-id) pair against a published per-repo known-capability list (benchmarks/build_benign_corpus.py); no admitted FP hidden in that list. The scanner excludes vendored/build dirs (venv, node_modules, site-packages, .git, dist, build, *.dist-info), so it does not false-flag a project's dependencies. |
python benchmarks/build_benign_corpus.py |
real repos |
| SCAN recall (held-out corpus) | 38/50 = 76% across 10 vuln classes (24% FN; 19/22 = 86% on real cases); 100% on SQL/CQL/cmd/RCE/CORS/trifecta/deserialization, 80% container-escape, 17% SSRF (conservative), 0% path-traversal (detector built-but-unregistered for precision) | python benchmarks/recall_corpus.py |
22 real + 28 labeled constructed |
| GUARD live-LLM block | Real model drives GUARD-wrapped tools; PII exfil blocked with witness; benign completes | python benchmarks/guard_live_llm.py |
live LLM |
| GUARD false-block rate | 0/6 = 0.0% on live-LLM benign tasks | python benchmarks/guard_falseblock.py |
live LLM |
| GUARD content-taint (encodings) | verbatim + base64/hex/url-encoded exfil caught; 0/12 benign false-taint; semantic-transform gap noted | python benchmarks/guard_taint_l4.py |
adversarial |
| GUARD CrewAI runtime adapter | benign ALLOW / trifecta BLOCK through crewai's own .run() |
python benchmarks/guard_crewai_runtime.py |
real framework |
| Trained admission (injection) detector | 67.2% recall @ 1.0% benign FP on held-out split (regex baseline 9.8%) | python benchmarks/admission_detector_eval.py |
single corpus (deepset, English, 546 rows) |
| Behavioral session-level FP | 3.75% benign session FP (session-level conformal) | python benchmarks/behavioral_eval.py |
SYNTHETIC |
| Behavioral drift detection | stationary false-drift 0%, gradual drift detected 92% | python benchmarks/drift_eval.py --seed 0 |
SYNTHETIC |
| Behavioral adaptive-evasion (L4) | slow-low 0.67 / probe 0.71 / mimicry 0.50; splitting gap noted | python benchmarks/behavioral_l4_evasion.py |
SYNTHETIC |
| Multi-agent memory integrity | live poison→detect-and-HOLD (re-reported every check until accept(), not self-healed) with causal trace on real chromadb, 0 FP on clean |
python benchmarks/memory_integrity_live.py |
real vector store |
| Multi-agent identity/cascade | 5/5 spoof rejected, 0/5 legit rejected; R0>1 worm-risk flagged | python benchmarks/multiagent_scenario_eval.py |
realistic synthetic |
Not-yet-validated (launch-gated — require real users/traces, not claimed): behavioral
precision on real production traffic; a design-partner production witness of GUARD; SCAN
precision at true user-repo-population scale; days-later multi-agent detection in a live
deployment. A published model-level PROVE ASR frontier is currently blocked by the only
reachable LLM endpoint's content filter (see DEFINITION_OF_DONE.md).
Red Team Engine
Unlike generic prompt injection testers, Lucin's red team is targeted:
- Scans your agent to identify its tools
- Crafts attacks that specifically use YOUR tool names
- Tests: data exfiltration, privilege escalation, injection, guardrail bypass
- Reports which attacks succeeded with evidence
lucin redteam ./my-agent/ --dry-run # Preview attacks without executing
Behavioral Monitor (ML)
🧪 Experimental. Validated on synthetic corpora only (session-level benign FP 3.75%, drift, and adaptive-evasion numbers in Validated Capabilities above). Precision on real production traces is not yet measured — see the launch-gated note.
Applies fraud-detection-grade anomaly scoring to agent actions:
- Multi-model ensemble (frequency + temporal + parameter + structural + sequence)
- Per-agent behavioral baselines (learns what's "normal")
- Session-level scoring with explainable factors
- Concept drift detection (adapts when behavior legitimately changes)
- Baseline persistence (survives restarts)
CI/CD Integration
GitHub Actions:
- uses: lucin/lucin@v1
with:
scan-path: './src/agents'
fail-on: 'high'
GitLab CI: See examples/ci/gitlab-ci.yml
Configuration
Create .lucin.yml in your project root:
scan:
fail_on: high
exclude_rules: [AG-010]
monitor:
baseline_actions: 50
alert_threshold: 60
webhooks:
slack_url: https://hooks.slack.com/services/...
Why Lucin?
After the Hugging Face breach (July 2026) — where an autonomous AI agent executed 17,000+ actions and breached production infrastructure — every team deploying AI agents needs to answer:
"What can our agents do that they shouldn't?"
Lucin answers that question in under 30 seconds.
Research-Verified
Detection algorithms verified against July 2026 state-of-art:
- De-obfuscation preprocessing (QFIRE pattern)
- Schema-based tool classification (SkillSieve approach)
- 5-model behavioral ensemble with sequence tracking (TraceAegis-inspired)
- Shannon entropy for unknown secret formats
- CORDON-MAS recommendations for memory poisoning defense
See ALGORITHM_VERIFICATION.md for full analysis with 12 cited papers.
Contributing
See CONTRIBUTING.md. Detection rules are pure functions: Agent → list[Finding]. Adding new rules is straightforward.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lucin-0.1.0-py3-none-any.whl.
File metadata
- Download URL: lucin-0.1.0-py3-none-any.whl
- Upload date:
- Size: 495.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1edd364a012563dceef06043ae25e84509a7bc2d95b50f3e6db111ae892e88a
|
|
| MD5 |
fdde4594636192bcfa9ea0fdf829aef3
|
|
| BLAKE2b-256 |
fb6e7aef5c1ec6cb2fd16284d54a39560a3a8b6b22903d3e3b2d84422e4e0b1c
|