llm-security-scanner

May 2, 2026 · View on GitHub

CI Python 3.10+ License: MIT Code style: ruff

Red-team toolkit for testing LLM applications against prompt injection, jailbreaks, data exfiltration, and tool abuse, with first-class Turkish payload support.

llm-security-scanner is an open-source security testing framework for applications built on top of large language models. Think of it as "OWASP ZAP for LLM apps": a pluggable engine that fires curated payloads at a target, evaluates whether the model misbehaved, and produces actionable reports. The project ships a Turkish payload library alongside English to serve the Turkish-speaking developer community.

⚠️ Responsible use. This toolkit is intended for defensive research, red-teaming systems you own or have authorisation to test, and educational exploration of LLM failure modes. Do not use it to attack systems you do not have permission to test.

Status

Active development. The core scanner, CLI, Turkish payload library, and HTTP/Ollama target adapters are functional and tested. Provider adapters (Anthropic, OpenAI), additional reporters (SARIF, HTML), and the LLM-as-judge evaluator land progressively toward v1.0.

Why another scanner?

ProjectDifferentiator of llm-security-scanner
GarakTurkish payload library + OWASP LLM Top 10 alignment baked into models
PromptFooSecurity-first focus rather than general eval harness
GiskardStandalone CLI + library, no platform lock-in

Architecture

The scanner is built around four pluggable abstractions, all defined as runtime-checkable Protocols in src/llm_security_scanner/:

  • Target (targets/base.py): adapter for an LLM provider (Anthropic, OpenAI, Ollama, generic HTTP). Translates a prompt into a TargetResponse.
  • Evaluator (evaluators/base.py): judges whether a payload succeeded. Implementations include rule-based matchers and LLM-as-judge.
  • Reporter (reporters/base.py): renders a ScanResult as Markdown, HTML, JSON, or SARIF.
  • Payloads (payloads/): YAML data files validated by the Pydantic Payload model. Non-developers can contribute payloads via PRs.

The core scanner depends only on these protocols, so the engine never knows which provider, evaluator, or output format is in use.

Payload schema

Every payload conforms to this schema (validated on load):

- id: jb-tr-001
  name: "Turkish DAN variant"
  category: jailbreak           # jailbreak | direct_injection | indirect_injection
                                # | sys_prompt_leak | data_exfil | tool_abuse | multi_turn
  owasp_llm_top10: LLM01
  severity: high                # low | medium | high | critical
  language: tr                  # ISO 639-1
  payload: |
    ...prompt text...
  success_indicators:
    - pattern: "DAN:"
      type: substring           # substring | regex | semantic
  references:
    - "https://..."
  tags: [role-play, dan]

CLI

llm-sec-scan ships with two commands:

# Browse the bundled payload library
llm-sec-scan list-payloads --language tr --category jailbreak

# Run a scan from a target config and write a Markdown report
llm-sec-scan scan \
  --target ./examples/ollama.yaml \
  --language tr \
  --format markdown \
  --output report.md

A target config is a small YAML file. ${VAR} references are expanded from the environment so secrets stay out of disk:

type: http
name: openai-chat
url: https://api.openai.com/v1/chat/completions
headers:
  Authorization: "Bearer ${OPENAI_API_KEY}"
  Content-Type: application/json
body_template:
  model: "gpt-4o-mini"
  messages:
    - role: user
      content: "{prompt}"
response_path: ["choices", 0, "message", "content"]

scan exits with code 1 whenever at least one vulnerable finding is detected, so it slots cleanly into CI.

Quick example

Run the bundled Turkish payloads against a local Ollama endpoint, score each response with the rule-based evaluator, and print a summary:

import asyncio

from llm_security_scanner import Scanner, load_payloads
from llm_security_scanner.evaluators import RuleBasedEvaluator
from llm_security_scanner.targets import HTTPTarget


async def main() -> None:
    target = HTTPTarget(
        name="local-ollama",
        url="http://localhost:11434/api/generate",
        body_template={"model": "llama3", "prompt": "{prompt}", "stream": False},
        response_path=["response"],
    )
    scanner = Scanner(
        target=target,
        evaluator=RuleBasedEvaluator(),
        concurrency=2,
    )
    result = await scanner.scan(load_payloads(languages=["tr"]))

    print(f"{result.target_name}: {result.vulnerable_count}/{result.total} vulnerable")
    for finding in result.findings:
        flag = "VULN" if finding.is_vulnerable else "ok  "
        print(f"  [{flag}] {finding.payload.id}: {finding.evaluation.reason}")


asyncio.run(main())

Development

Requirements: Python 3.10+ and uv (or pip).

# Clone and install
git clone https://github.com/tugkanboz/llm-security-scanner.git
cd llm-security-scanner
uv pip install -e ".[dev]"

# Run tests
pytest

# Lint and type-check
ruff check .
mypy
``$

## \text{Roadmap}

- [\text{x}] \text{Project} \text{skeleton}: \text{tooling}, \text{base} \text{protocols}, \text{core} \text{models}
- [\text{x}] \text{Payload} \text{loader} \text{with} \text{YAML} \text{validation}
- [\text{x}] \text{Seed} \text{payload} \text{library} (5 \text{languages}  \times  3 \text{categories}: \text{EN}, \text{TR}, \text{DE}, \text{ES}, \text{FR})
- [\text{x}] \text{Generic} \text{HTTP} \text{target} \text{adapter}
- [\text{x}] \text{Rule}-\text{based} \text{evaluator} (\text{substring} + \text{regex})
- [\text{x}] \text{Scanner} \text{core} \text{orchestration} \text{with} \text{bounded} \text{concurrency}
- [\text{x}] \text{Reporters}: \text{Markdown} \text{and} \text{JSON}
- [\text{x}] \text{CLI} ($llm-sec-scan`) with `scan` and `list-payloads`
- [x] CI: lint, type-check, tests on every PR
- [ ] Native-speaker review of DE/ES/FR payload sets
- [ ] Provider adapters: Anthropic, OpenAI, Ollama
- [ ] LLM-as-judge evaluator
- [ ] Reporters: SARIF and HTML
- [ ] v1.0 stabilisation and PyPI release

## Translation note

The Turkish (`tr`) payloads are author-written. The German (`de`),
Spanish (`es`), and French (`fr`) sets were initially produced with AI
assistance and have **not yet been reviewed by native speakers**. PRs
improving phrasing, idiom, or success-indicator regexes from native
speakers are very welcome. See `CONTRIBUTING.md`.

## Contributing

Contributions are welcome, payloads especially. See
[`CONTRIBUTING.md`](CONTRIBUTING.md) for guidelines and the payload
schema. Security issues should follow [`SECURITY.md`](SECURITY.md);
participation is governed by the [code of conduct](CODE_OF_CONDUCT.md).

## Türkçe

`llm-security-scanner`, LLM uygulamalarını prompt injection, jailbreak ve veri
sızdırma saldırılarına karşı test eden açık kaynaklı bir red-team aracıdır.
Türkçe payload kütüphanesiyle Türkçe konuşan geliştirici topluluğunu
hedefler. Proje aktif geliştirme aşamasındadır; katkılara, özellikle Türkçe
payload katkılarına açıktır.

## Licence

MIT, see [`LICENSE`](LICENSE).