Agent-first security testing framework
Project description
Leshy
Shapeshifting trickster, forest spirit known for misleading anyone who crosses his path. Can he mislead your agent?
Security testing framework that generates LangGraph guardrail nodes. Test your agent. Find vulnerabilities. Get guardrail code. One tool.
What is Leshy?
Leshy is a security testing framework built for AI agents. It:
- Tests your agent against 28 attacks across 6 categories (prompt injection, jailbreak, data extraction, excessive agency, safety, DoS)
- Evaluates responses using pattern matching or LLM-as-judge (any provider via litellm)
- Generates LangGraph guardrail nodes — drop-in
input_guardrailandoutput_guardrailfunctions for yourStateGraph
The Flow
leshy init → generates leshy_config.yaml + leshy/ folder
↓
leshy run --test → runs security tests against your agent
↓ results saved to leshy/runs/
leshy run --guardrails → runs tests + generates leshy/runs/guardrail_node.py
↓
wire into StateGraph → import guardrail functions into your LangGraph workflow
Quick Start
# 1. Install
pip install leshy
# 2. Generate config
leshy init
# 3. (Optionally) Edit leshy_config.yaml with your target URL and API key
# 4. Run tests + generate guardrails
leshy run
This creates a leshy/ folder with test templates organized by category, runs all security tests, and saves results + guardrail code to leshy/runs/.
Installation
pip install leshy # core (pattern evaluator only)
pip install "leshy[llm]" # + LLM judge & LLM buffs (via litellm)
pip install "leshy[langgraph]" # + LangGraph target support
pip install "leshy[all]" # everything
Supported LLM Providers
Leshy uses litellm for LLM features (judge evaluation and LLM buffs). Any litellm-supported provider works:
| Provider | Model string | Env variable |
|---|---|---|
| OpenAI | gpt-4o-mini, gpt-4o |
OPENAI_API_KEY |
| Anthropic | claude-sonnet-4-5-20250929 |
ANTHROPIC_API_KEY |
gemini/gemini-1.5-flash |
GEMINI_API_KEY |
|
| Azure | azure/gpt-4o-mini |
AZURE_API_KEY + AZURE_API_BASE |
| AWS Bedrock | bedrock/anthropic.claude-3-haiku |
AWS credentials |
Set llm_model in your config to choose the provider:
llm_model: claude-sonnet-4-5-20250929 # or gpt-4o-mini, gemini/gemini-1.5-flash, etc.
Usage
Run security tests
leshy run config.yaml --test [--tag TAG] [--verbose] [--save-results results.json]
Run tests + generate guardrail nodes
leshy run config.yaml --guardrails [-o path/to/guardrail_node.py]
By default, guardrails are written to leshy/runs/guardrail_node.py.
Generate guardrails from existing results
leshy run --from-results results.json [-o guardrail_node.py]
Interactive mode
leshy run config.yaml
Prompts you to choose between running tests or running tests + generating guardrails.
Exit codes: 0 = clean, 1 = vulnerabilities found, 2 = error.
List available plugins
leshy list attacks
leshy list evaluators
leshy list buffs
Configuration
Minimal YAML config:
name: Quick Scan
llm_model: gpt-4o-mini
# Send 5 payloads in parallel per test case
concurrency: 5
target:
type: http
url: https://my-agent.example.com/chat
headers:
Authorization: "Bearer ${API_KEY}"
body_template: '{"prompt": "{{payload}}"}' # {{payload}} = attack text
# For multi-turn tests, add session tracking:
# body_template: '{"prompt": "{{payload}}", "session_id": "{{session_id}}"}'
response_path: "$.response"
loggers:
- console
- json_file
tests_dir: leshy/templates
The tests_dir points to a folder with per-category test YAML files (created by leshy init or leshy generate).
Environment variables
Use ${VAR_NAME} in YAML for secrets. These are resolved from your environment before parsing.
Presets
Use preset: openai_chat for OpenAI-compatible APIs (no body_template needed).
LangGraph Target
Test LangGraph agents deployed via LangGraph Platform:
pip install "leshy[langgraph]"
target:
type: langgraph
url: http://localhost:8123
headers:
x-assistant-id: "my-agent"
Set LANGSMITH_API_KEY for hosted deployments.
Multi-turn
tests:
- name: Escalation Test
multi_turn: true
max_turns: 4
attacks:
- name: jailbreak.escalation
Custom payloads
tests:
- name: Custom
attacks:
- name: prompt_injection.direct
custom_payloads:
- "Your custom payload here"
Buffs (Payload Transformers)
Apply transformations to payloads before sending:
tests:
- name: Encoded Injection
buffs:
- name: base64
attacks:
- name: prompt_injection.direct
Built-in buffs: base64, rot13, hex, leetspeak, reverse, uppercase, lowercase, prefix, suffix, wrap
LLM buffs (require leshy[llm]): rephrase, translate
Parallel Execution
tests:
- name: Fast Injection Test
concurrency: 10
attacks:
- name: prompt_injection.direct
Built-in Attacks
| Category | Attack | Description |
|---|---|---|
| Prompt Injection | prompt_injection.direct |
Instruction override attempts |
prompt_injection.indirect |
Injection via simulated external data | |
prompt_injection.context_overflow |
Context flooding | |
prompt_injection.delimiter |
Delimiter/format breakout | |
| Jailbreak | jailbreak.roleplay |
DAN, personas, role adoption |
jailbreak.hypothetical |
Hypothetical scenarios | |
jailbreak.encoding |
Base64, ROT13, leetspeak | |
jailbreak.escalation |
Multi-turn trust escalation | |
| Data Extraction | data_extraction.system_prompt |
System prompt leakage |
data_extraction.pii |
PII leakage probing | |
data_extraction.credentials |
Credential extraction | |
| Excessive Agency | excessive_agency.tool_injection |
Dangerous tool/command execution |
excessive_agency.parameter_manipulation |
Unauthorized parameter changes | |
excessive_agency.privilege_escalation |
Social engineering for elevated access | |
excessive_agency.chained_tools |
Multi-step tool abuse | |
excessive_agency.implicit |
Subtle unauthorized tool triggers | |
| Safety | safety.toxicity |
Toxic/hateful content generation |
safety.harmful_content |
Dangerous instructions (weapons, drugs) | |
safety.illegal |
Illegal activity assistance | |
safety.self_harm |
Self-harm/suicide content | |
safety.misinformation |
Fake news, propaganda | |
safety.policy_bypass |
Creative policy circumvention | |
| DoS | dos.context_exhaustion |
Large output generation |
dos.recursive |
Recursive/infinite patterns | |
dos.expensive_computation |
Resource-intensive requests | |
dos.infinite_loop |
Unbounded generation | |
dos.memory_exhaustion |
Memory exhaustion attacks | |
dos.tool_spam |
Excessive tool calls |
Evaluators
- pattern — Regex/keyword matching with configurable patterns and match modes
- llm_judge — LLM-as-judge via litellm (supports OpenAI, Anthropic, Google, Azure, etc.)
Loggers
- console — Rich terminal output (default)
- json_file — Structured JSON results
- html — Interactive HTML report
- langfuse — Trace export to Langfuse (
pip install "leshy[langfuse]") - langsmith — Trace export to LangSmith (
pip install "leshy[langsmith]")
Development
git clone https://github.com/bards-ai/leshy.git
cd leshy
uv sync --all-extras
uv run pytest
uv run ruff check src/
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 Distribution
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 leshy-0.1.0.tar.gz.
File metadata
- Download URL: leshy-0.1.0.tar.gz
- Upload date:
- Size: 2.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aae029078b200f98ab9f1c38c40aab62690b7a2a85a2011e7fc287246550b3bc
|
|
| MD5 |
34cd381dedaf73ddbea54b11bc58b378
|
|
| BLAKE2b-256 |
ffa87e52069c7c02492ca3ed270ef6bc2faf2ac44b1cbce010aa0080b84b3671
|
Provenance
The following attestation bundles were made for leshy-0.1.0.tar.gz:
Publisher:
release.yml on bards-ai/leshy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leshy-0.1.0.tar.gz -
Subject digest:
aae029078b200f98ab9f1c38c40aab62690b7a2a85a2011e7fc287246550b3bc - Sigstore transparency entry: 930172953
- Sigstore integration time:
-
Permalink:
bards-ai/leshy@6665a8e536dfda26b012d23b823ca1b97604e317 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bards-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6665a8e536dfda26b012d23b823ca1b97604e317 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file leshy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: leshy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 75.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b72636487228b731ba8ba6baf87c68b8ab5cf5883050e2665040a21206e7b1e
|
|
| MD5 |
0ecfec1365a82e1d40a7d79fd094b1a7
|
|
| BLAKE2b-256 |
c825598351578cc79ac7ff0148e9335770e985d7eecaf15e8078c082b4397982
|
Provenance
The following attestation bundles were made for leshy-0.1.0-py3-none-any.whl:
Publisher:
release.yml on bards-ai/leshy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
leshy-0.1.0-py3-none-any.whl -
Subject digest:
0b72636487228b731ba8ba6baf87c68b8ab5cf5883050e2665040a21206e7b1e - Sigstore transparency entry: 930172988
- Sigstore integration time:
-
Permalink:
bards-ai/leshy@6665a8e536dfda26b012d23b823ca1b97604e317 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bards-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6665a8e536dfda26b012d23b823ca1b97604e317 -
Trigger Event:
workflow_dispatch
-
Statement type: