PromptShield / README.md
gujjarkaleem37's picture
Update README.md
e87ad18 verified
|
Raw
History Blame Contribute Delete
5.06 kB
---
title: PromptShield
emoji: πŸ›‘οΈ
colorFrom: blue
colorTo: gray
sdk: gradio
app_file: app.py
pinned: false
sdk_version: 6.20.0
---
# PromptShield
A lightweight security layer that detects prompt-injection / jailbreak attempts
before they reach an LLM-powered application. Built as a standalone,
deployable API + demo, and designed to sit in front of existing LLM apps
(tested here against Consent Guardian and Prof-Scope-AI).
## How it works
```
User prompt -> Preprocessing -> Feature extraction -> Detection engine -> Risk gate
(TF-IDF + heuristics) (ML classifier)
|
Allow ------+------ Block
(forward) (log + alert)
```
- **Feature extraction**: TF-IDF over the prompt text, combined with
hand-crafted heuristic signals (presence of override phrases like
"ignore previous instructions", imperative-mood sentence starts,
suspicious formatting markers like `###SYSTEM`).
- **Detection engine**: a Random Forest classifier (selected over Logistic
Regression for higher recall on the injection class -- in security, a
missed attack is worse than a false alarm).
- **Risk gate**: prompts scoring above 0.5 probability are blocked and
logged; below that, they're forwarded to the downstream app.
## Results
| Test | Accuracy | Notes |
|---|---|---|
| Held-out test split (same template distribution) | ~99-100% | Expected to be inflated -- same phrasing patterns as training |
| **Hand-written novel prompts (out-of-distribution)** | **12/12 (100%)** | More honest signal -- zero overlap with training templates, confidence scores realistically in the 0.4-0.8 range rather than saturated at 0/1 |
**Important honesty note for your write-up**: the training data here is
template-generated (see `src/build_dataset.py`) because this environment
couldn't reach Hugging Face Hub to pull the public `deepset/prompt-injections`
dataset. The novel-prompt test is a genuine generalization check, but a
larger, real-world dataset (see below) would make the results far more
defensible for a research write-up or professor-facing project.
## Upgrading to a real dataset (do this on Colab / your own machine)
This sandbox can't reach huggingface.co, so run this step separately:
```python
# pip install datasets
from src.build_dataset import load_real_dataset
load_real_dataset() # pulls deepset/prompt-injections, saves to data/prompts_real.csv
```
Then retrain with `train.py` pointed at `data/prompts_real.csv` instead.
Consider also mixing in your synthetic data for extra coverage of
paraphrase variety.
## Project structure
```
PromptShield/
β”œβ”€β”€ app.py # FastAPI + Gradio, deployment entry point
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ data/
β”‚ └── prompts.csv # synthetic training data
β”œβ”€β”€ models/
β”‚ β”œβ”€β”€ classifier.joblib
β”‚ └── vectorizer.joblib
└── src/
β”œβ”€β”€ build_dataset.py # dataset generation (+ real-dataset loader)
β”œβ”€β”€ features.py # TF-IDF + heuristic feature extraction
β”œβ”€β”€ train.py # training + evaluation
└── novel_test.py # honest out-of-distribution test
```
## Running locally
```bash
pip install -r requirements.txt
python src/build_dataset.py # generate data
python src/train.py # train + evaluate
python src/novel_test.py # sanity-check generalization
python app.py # launch API + demo at localhost:7860
```
## Deploying to Hugging Face Spaces
1. Create a new Space, SDK = Gradio.
2. Upload this entire folder (or push via git).
3. Spaces auto-detects `app.py` as the entry point -- no extra config needed.
4. Your guardrail is now live at `https://huggingface.co/spaces/<you>/<space-name>`,
with the `/check` endpoint callable from any other app.
## Calling it from another app (e.g. Consent Guardian, Prof-Scope-AI)
This Space uses Gradio's built-in API (no separate FastAPI server -- this
avoids a port conflict with Hugging Face's ZeroGPU hardware, which is the
only free tier available on new accounts).
**Option A: raw HTTP (two-step call -- POST then GET the result)**
```python
import requests
# Step 1: submit the prompt
resp = requests.post(
"https://<your-space>.hf.space/gradio_api/call/check",
json={"data": [user_input]}
)
event_id = resp.json()["event_id"]
# Step 2: fetch the result
result = requests.get(
f"https://<your-space>.hf.space/gradio_api/call/check/{event_id}"
)
# result.text looks like: 'event: complete\ndata: ["blocked", 0.945]\n'
```
**Option B: gradio_client (simpler, recommended)**
```python
# pip install gradio_client
from gradio_client import Client
client = Client("https://<your-space>.hf.space")
decision, risk_score = client.predict(user_input, api_name="/check")
if decision == "blocked":
# reject / log / alert instead of forwarding to the LLM
...
```