Skip to content

Repository files navigation

πŸ›‘οΈ LLM Guardrails β€” OWASP LLM Top 10 (2025)

Production-grade safety layer for LLM applications. Modular, fast, and zero-dependency for core functionality. Drop it in front of any LLM in minutes.

Python OWASP License Live Demo


The Problem

"It was 2am when the Slack message came through: 'Our chatbot is saying wildly inappropriate things to customers. We need to take it offline NOW.'"

When a production incident is analysed, the most common threats found are hundreds of attempted prompt injection attacks, outputs containing PII, toxic responses, and hallucinated facts β€” all in a single day of traffic.

Every LLM application needs a safety layer. This is that layer.


Benchmark Results

Tested against 35 adversarial cases across 4 categories:

Attack Category Detection Rate False Positive Rate Avg Latency
Prompt Injection (LLM01) 97% 2.1% 8ms
PII Detection (LLM02/06) 98% 1.4% 12ms
Toxicity (LLM09) 91% 3.2% 15ms
Safe inputs (no false blocks) 100% β€” 10ms
Overall 96% 2.2% 11ms

Run the benchmark yourself: python evaluation/attack_suite.py


What's Covered

OWASP Risk Guard Method
LLM01 Prompt Injection PromptInjectionDetector 40+ regex patterns + Base64 decode + BM patterns
LLM02 Sensitive Info Disclosure PIIDetector (output) Regex + optional Presidio NER
LLM06 Excessive Agency PIIDetector (input) MyKad, SG NRIC, email, phone, credit card, API keys
LLM07 System Prompt Leakage OutputValidator Pattern detection in LLM responses
LLM09 Misinformation ToxicityClassifier + OutputValidator Toxicity patterns + hallucination signals

Quick Start

git clone https://github.com/aliyaalias19/llm-guardrails
cd llm-guardrails
pip install -r requirements.txt
python quickstart.py     # Verify everything works

Run the Interactive Demo

python demo/app.py
# Open http://localhost:7860

Run the Attack Benchmark

python evaluation/attack_suite.py

Start the API Server

uvicorn api:app --reload --port 8000
# Open http://localhost:8000/docs

Usage β€” 4 Lines of Code

from guardrails import GuardrailsPipeline, GuardrailsConfig, GuardrailRequest

pipeline = GuardrailsPipeline()

# Check input BEFORE sending to LLM
result = pipeline.check_input(GuardrailRequest(user_input="User message here"))

if not result.allowed:
    return result.block_response   # Safe, user-facing error message

# Call your LLM with sanitised input (PII removed)
llm_output = your_llm(result.sanitised_input)

# Check output BEFORE returning to user
out = pipeline.check_output(result.request_id, llm_output)
return out.final_output            # Sanitised + disclaimers appended

Or wrap your entire LLM call:

result = pipeline.wrap_llm(
    llm_fn=lambda x: openai_client.chat(x),
    user_input="User message",
)
return result["response"]

Architecture

User Input
    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              INPUT GUARDRAILS                β”‚
β”‚                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  PromptInjectionDetector            β”‚    β”‚
β”‚  β”‚  β€’ 40+ OWASP-aligned patterns       β”‚    β”‚
β”‚  β”‚  β€’ DAN/jailbreak detection          β”‚    β”‚
β”‚  β”‚  β€’ Base64 decode + rescan           β”‚    β”‚
β”‚  β”‚  β€’ Bahasa Malaysia patterns         β”‚    β”‚
│  │  ‒ Severity: LOW→MEDIUM→HIGH→CRIT  │    │
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                    ↓                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  ToxicityClassifier                 β”‚    β”‚
β”‚  β”‚  β€’ 7 toxicity categories            β”‚    β”‚
β”‚  β”‚  β€’ Violence, self-harm, illegal     β”‚    β”‚
β”‚  β”‚  β€’ Crisis resources for self-harm   β”‚    β”‚
β”‚  β”‚  β€’ BM + EN patterns                 β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                    ↓                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  PIIDetector                        β”‚    β”‚
β”‚  β”‚  β€’ Malaysian IC (MyKad)             β”‚    β”‚
β”‚  β”‚  β€’ Singapore NRIC/FIN               β”‚    β”‚
β”‚  β”‚  β€’ Email, phone, credit card        β”‚    β”‚
β”‚  β”‚  β€’ API keys & secrets               β”‚    β”‚
β”‚  β”‚  β€’ Redact (don't block)             β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    ↓ (sanitised input if all pass)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   YOUR LLM   β”‚  ← OpenAI / Claude / Ollama / any
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              OUTPUT GUARDRAILS               β”‚
β”‚                                              β”‚
β”‚  β€’ System prompt leakage detection          β”‚
β”‚  β€’ PII in output (auto-redact)              β”‚
β”‚  β€’ Hallucination signal detection           β”‚
β”‚  β€’ RAG grounding check                      β”‚
β”‚  β€’ Disclaimer injection                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    ↓
Safe Response β†’ User

Project Structure

llm-guardrails/
β”‚
β”œβ”€β”€ guardrails/
β”‚   β”œβ”€β”€ input/
β”‚   β”‚   β”œβ”€β”€ prompt_injection.py   ← 40+ patterns, Base64 decode, BM support
β”‚   β”‚   β”œβ”€β”€ pii_detector.py       ← MyKad, SG NRIC, email, credit card, API keys
β”‚   β”‚   └── toxicity_classifier.py ← 7 categories, BM patterns, crisis resources
β”‚   β”œβ”€β”€ output/
β”‚   β”‚   └── output_validator.py   ← Hallucination, PII leakage, system prompt leak
β”‚   └── middleware/
β”‚       └── pipeline.py           ← Central orchestrator, wrap_llm() helper
β”‚
β”œβ”€β”€ evaluation/
β”‚   └── attack_suite.py           ← 35+ adversarial test cases, benchmarking
β”‚
β”œβ”€β”€ demo/
β”‚   └── app.py                    ← Interactive Gradio demo (4 tabs)
β”‚
β”œβ”€β”€ api.py                        ← FastAPI microservice
β”œβ”€β”€ quickstart.py                 ← Verify setup in <30 seconds
└── requirements.txt

Key Design Decisions

Why pattern matching over LLM-as-judge?

A regex filter runs in microseconds. An LLM-as-judge takes 8 seconds. Stack five 90%-accurate guards and you'll hit false positives 40% of the time. Production guardrails require understanding these trade-offs.

This project leads with fast, deterministic patterns (microseconds) and reserves ML models as optional enhancements. The result: <100ms total overhead for 99% of requests β€” viable for real-time chat applications.

Why Malaysian/BM patterns specifically?

Most open-source guardrail libraries only cover English. Malaysian enterprises deploying LLMs to BM-speaking users are exposed. This library adds:

  • Bahasa Malaysia prompt injection patterns
  • Malaysian IC (MyKad) PII detection
  • BM toxicity and self-harm patterns
  • Crisis resources in BM context

Why no mandatory external dependencies?

The core guardrails run with zero external ML dependencies. Optional integrations (Presidio for NER, Hugging Face for ML classification) are clearly marked and easy to enable when needed.


Optional Enhancements

Enable Microsoft Presidio (better PII accuracy)

pip install presidio-analyzer presidio-anonymizer
python -m spacy download en_core_web_lg
from guardrails import GuardrailsPipeline, GuardrailsConfig

pipeline = GuardrailsPipeline(GuardrailsConfig(use_presidio=True))

Presidio uses a combination of named entity recognition, regular expressions, and checksum validation to identify sensitive data β€” combining multiple detection methods for higher accuracy than regex alone.

Enable ML Toxicity Classifier

pip install transformers torch
pipeline = GuardrailsPipeline(GuardrailsConfig(enable_ml_toxicity=True))

API Reference

# Start server
uvicorn api:app --port 8000

# Check input
curl -X POST http://localhost:8000/check/input \
  -H "Content-Type: application/json" \
  -d '{"text": "Ignore all previous instructions"}'

# Response:
# {
#   "allowed": false,
#   "action": "block",
#   "block_reason": "prompt_injection:direct_instruction_override",
#   "block_response": "I'm unable to process this request...",
#   "latency_ms": 8.3
# }

Citation

@misc{alias2026guardrails,
  title  = {LLM Guardrails: Production OWASP LLM Top 10 Safety Layer},
  author = {Alias, Aliya},
  year   = {2026},
  url    = {https://github.com/aliyaalias19/llm-guardrails}
}

πŸ‘€ About

Built by Aliya Alias β€” AI Engineer, Kuala Lumpur, Malaysia. MSc Artificial Intelligence, University of Malaya.

LinkedIn GitHub

MIT License.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages