Skip to content

Commit ae9b950

Browse files
authored
vigillm (#263)
2 parents 156770c + f47ebbd commit ae9b950

File tree

8 files changed

+235
-7
lines changed

8 files changed

+235
-7
lines changed

demo/demo_config.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ providers:
3434

3535
rules:
3636
input:
37-
- name: "prompt_injection_example"
38-
type: "prompt_injection"
37+
- name: "VigillLM"
38+
type: "vigilllm"
3939
enabled: true
40+
order_number: 2
4041
config:
41-
plugin_name: "prompt_injection_llm"
42-
threshold: 0.85
42+
plugin_name: "vigilllm"
43+
threshold: 0.7
44+
relation: ">"
4345
action:
4446
type: "block"

demo/docker-compose.yml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
services:
22
openshield:
33
build:
4-
context: ../
5-
dockerfile: Dockerfile
4+
context: ../
5+
dockerfile: Dockerfile
66
environment:
77
- ENV=production
88
- PORT="3005"
@@ -14,22 +14,37 @@ services:
1414
links:
1515
- redis
1616
- postgres
17+
- vigilllm
1718
volumes:
1819
- ./demo_config.yaml:/app/config.yaml
1920
depends_on:
2021
postgres:
2122
condition: service_healthy
2223

24+
vigilllm:
25+
build:
26+
context: ../services/vigilllm
27+
dockerfile: Dockerfile
28+
environment:
29+
- OPENAI_API_KEY=${OPENAI_API_KEY}
30+
ports:
31+
- "5000:5000"
32+
volumes:
33+
- vigil_data:/app/data
34+
2335
rule:
2436
build:
2537
context: ../services/rule
2638
dockerfile: Dockerfile
2739
environment:
2840
- HF_HOME=/app/hf_cache
41+
- VIGILLLM_API_URL=http://vigilllm:5000
2942
volumes:
3043
- ./volumes/rule:/app/cache
3144
ports:
3245
- "8000:8000"
46+
depends_on:
47+
- vigilllm
3348

3449
cache:
3550
build:
@@ -44,7 +59,6 @@ services:
4459
ports:
4560
- "8082:8080"
4661

47-
4862
redis:
4963
image: "valkey/valkey:8.0.1-alpine"
5064
restart: always
@@ -71,3 +85,6 @@ services:
7185
restart: always
7286
ports:
7387
- 8085:8080
88+
89+
volumes:
90+
vigil_data:

lib/rules/input.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type InputTypes struct {
2323
Moderation string
2424
LlamaGuard string
2525
PromptGuard string
26+
VigilLLM string
2627
}
2728

2829
var inputTypes = InputTypes{
@@ -33,6 +34,7 @@ var inputTypes = InputTypes{
3334
Moderation: "moderation",
3435
LlamaGuard: "llama_guard",
3536
PromptGuard: "prompt_guard",
37+
VigilLLM: "vigilllm",
3638
}
3739

3840
type Rule struct {
@@ -313,6 +315,8 @@ func handleRuleAction(inputConfig lib.Rule, rule RuleResult, ruleType string, me
313315
log.Printf("%s detection result: Match=%v, Score=%f", ruleType, rule.Match, rule.Inspection.Score)
314316

315317
switch ruleType {
318+
case inputTypes.VigilLLM:
319+
return genericHandler(inputConfig, rule)
316320
case inputTypes.InvisibleChars:
317321
return genericHandler(inputConfig, rule)
318322
case inputTypes.LanguageDetection:

services/rule/src/plugins/vigilllm.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""
2+
VigillLM plugin for rule server to detect prompt injections and other LLM threats.
3+
This plugin uses VigillLM's API endpoint to analyze prompts.
4+
"""
5+
6+
import logging
7+
import requests
8+
import os
9+
from typing import Dict, Any
10+
11+
from utils.logger_config import setup_logger
12+
13+
logger = setup_logger(__name__)
14+
15+
16+
def get_vigilllm_url():
17+
url = os.getenv("VIGILLLM_API_URL")
18+
if not url:
19+
logger.error("VIGILLLM_API_URL environment variable not set")
20+
raise ValueError("VIGILLLM_API_URL environment variable not set")
21+
return url
22+
23+
24+
class VigillLMAnalyzer:
25+
26+
27+
def __init__(self):
28+
self.api_url = get_vigilllm_url().rstrip('/')
29+
self.analyze_endpoint = f"{self.api_url}/analyze/prompt"
30+
logger.info(f"Initialized VigillLM analyzer with API URL: {self.api_url}")
31+
32+
def analyze_prompt(self, text: str) -> Dict[str, Any]:
33+
34+
try:
35+
logger.debug(f"Sending prompt to VigillLM for analysis: {text[:100]}...")
36+
37+
response = requests.post(
38+
self.analyze_endpoint,
39+
json={"prompt": text},
40+
timeout=30
41+
)
42+
43+
response.raise_for_status()
44+
result = response.json()
45+
46+
logger.debug(f"Received VigillLM analysis result: {result}")
47+
return result
48+
49+
except requests.exceptions.RequestException as e:
50+
error_msg = f"Error calling VigillLM API: {str(e)}"
51+
logger.error(error_msg)
52+
raise RuntimeError(error_msg)
53+
54+
55+
56+
analyzer = None
57+
58+
59+
def handler(text: str, threshold: float, config: Dict[str, Any]) -> Dict[str, Any]:
60+
61+
global analyzer
62+
63+
try:
64+
if analyzer is None:
65+
analyzer = VigillLMAnalyzer()
66+
logger.info("Initialized VigillLM analyzer")
67+
68+
69+
result = analyzer.analyze_prompt(text)
70+
71+
72+
scanners = result.get('results', {})
73+
risk_score = 0.0
74+
75+
if 'scanner:transformer' in scanners:
76+
transformer_matches = scanners['scanner:transformer'].get('matches', [])
77+
if transformer_matches and len(transformer_matches) > 0:
78+
# Use the first transformer match score
79+
risk_score = transformer_matches[0]['score']
80+
81+
return {
82+
"check_result": risk_score > threshold,
83+
"score": risk_score,
84+
"details": {
85+
"messages": result.get('messages', []),
86+
"scanners": result.get('results', {}),
87+
"uuid": result.get('uuid'),
88+
"timestamp": result.get('timestamp')
89+
}
90+
}
91+
92+
except Exception as e:
93+
logger.error(f"Error in VigillLM analysis: {str(e)}")
94+
return {
95+
"check_result": False,
96+
"score": 0.0,
97+
"details": {"error": str(e)}
98+
}

services/vigilllm/Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM python:3.10-slim
2+
3+
4+
WORKDIR /app
5+
6+
7+
RUN apt-get update && apt-get install --no-install-recommends -y \
8+
automake autoconf build-essential libtool libc-dev make flex gcc \
9+
pkg-config libssl-dev curl unzip git git-lfs bison \
10+
&& rm -rf /var/lib/apt/lists/*
11+
12+
13+
RUN echo "Installing YARA from source ..." \
14+
&& curl -Lo yara.zip https://github.com/VirusTotal/yara/archive/refs/tags/v4.3.2.zip \
15+
&& unzip yara.zip \
16+
&& cd yara-4.3.2 \
17+
&& ./bootstrap.sh \
18+
&& ./configure \
19+
&& make \
20+
&& make install \
21+
&& make check \
22+
&& cd .. \
23+
&& rm -rf yara.zip yara-4.3.2
24+
25+
26+
RUN git clone https://github.com/deadbits/vigil-llm.git .
27+
28+
29+
COPY packages.txt .
30+
31+
32+
RUN echo "Installing Python dependencies ... " \
33+
&& pip install --no-cache-dir -r packages.txt
34+
35+
36+
COPY generate_config.sh /app/generate_config.sh
37+
RUN chmod +x /app/generate_config.sh
38+
39+
40+
41+
EXPOSE 5000
42+
43+
44+
COPY entrypoint.sh /entrypoint.sh
45+
RUN chmod +x /entrypoint.sh
46+
47+
48+
ENTRYPOINT ["/entrypoint.sh", "python", "-m", "vigil.vigil", "-c", "conf/server.conf"]

services/vigilllm/entrypoint.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
# Generate the configuration at runtime using the current environment variables
4+
echo "Generating configuration with OPENAI_API_KEY..."
5+
/app/generate_config.sh
6+
7+
8+
9+
echo "Loading datasets ..."
10+
python loader.py --config /app/conf/server.conf --dataset deadbits/vigil-instruction-bypass-ada-002
11+
python loader.py --config /app/conf/server.conf --dataset deadbits/vigil-jailbreak-ada-002
12+
echo " "
13+
echo "Starting API server ..."
14+
cd /app
15+
python vigil-server.py --conf conf/server.conf
16+

services/vigilllm/generate_config.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/bash
2+
3+
# Create config file with the OPENAI_API_KEY from environment
4+
cat > /app/conf/server.conf << EOL
5+
[main]
6+
use_cache = true
7+
cache_max = 500
8+
9+
[embedding]
10+
model = openai
11+
openai_key = ${OPENAI_API_KEY}
12+
13+
[vectordb]
14+
collection = data-openai
15+
db_dir = /app/data/vdb
16+
n_results = 5
17+
18+
[auto_update]
19+
enabled = true
20+
threshold = 3
21+
22+
[scanners]
23+
input_scanners = transformer,vectordb,sentiment,yara
24+
output_scanners = similarity,sentiment
25+
26+
[scanner:yara]
27+
rules_dir = /app/data/yara
28+
29+
[scanner:vectordb]
30+
threshold = 0.4
31+
32+
[scanner:transformer]
33+
model = deepset/deberta-v3-base-injection
34+
threshold = 0.98
35+
36+
[scanner:similarity]
37+
threshold = 0.4
38+
39+
[scanner:sentiment]
40+
threshold = 0.7
41+
EOL
42+
43+
echo "Generated server.conf with OPENAI_API_KEY"

services/vigilllm/packages.txt

5.28 KB
Binary file not shown.

0 commit comments

Comments
 (0)