Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 5395c6b7a0 build(deps): bump certifi from 2024.2.2 to 2024.7.4
Bumps [certifi](https://github.com/certifi/python-certifi) from 2024.2.2 to 2024.7.4.
- [Commits](https://github.com/certifi/python-certifi/compare/2024.02.02...2024.07.04)

---
updated-dependencies:
- dependency-name: certifi
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-06 01:35:57 +00:00
6 changed files with 98 additions and 238 deletions
+9
View File
@@ -26,6 +26,7 @@
- LLM API integration and stress testing 🛠️
- Wide range of fuzzing and attack techniques 🌀
| Tool | Source | Integrated |
|-------------------------|-------------------------------------------------------------------------------|------------|
| Garak | [leondz/garak](https://github.com/leondz/garak) | ✅ |
@@ -34,8 +35,11 @@
| Custom Huggingface Datasets | markush1/LLM-Jailbreak-Classifier | ✅ |
| Local CSV Datasets | - | ✅ |
Note: Please be aware that Agentic Security is designed as a safety scanner tool and not a foolproof solution. It cannot guarantee complete protection against all possible threats.
## 📦 Installation
To get started with Agentic Security, simply install the package using pip:
@@ -69,6 +73,7 @@ agentic_security --port=PORT --host=HOST
## UI 🧙
<img width="100%" alt="booking-screen" src="https://res.cloudinary.com/do9qa2bqr/image/upload/v1713002396/1-ezgif.com-video-to-gif-converter_s2hsro.gif">
## LLM kwargs
@@ -300,7 +305,11 @@ Agentic Security is released under the Apache License v2.
## Contact us
## 🤝 Schedule a 1-on-1 Session
<a href="https://cal.com/alexander-myasoedov-go2tfs/30min"><img src="https://cal.com/book-with-cal-dark.svg" alt="Book us with Cal.com"></a>
Book a 1-on-1 Session with the founders, to discuss any issues, provide feedback, or explore how we can improve agentic_security for you.
## Repo Activity
+9 -49
View File
@@ -7,7 +7,7 @@ REGISTRY = [
"tokens": 224196,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/ShawnMenz/DAN_jailbreak",
},
@@ -17,7 +17,7 @@ REGISTRY = [
"tokens": 6988,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/deepset/prompt-injections",
},
@@ -27,7 +27,7 @@ REGISTRY = [
"tokens": 26971,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/rubend18/ChatGPT-Jailbreak-Prompts",
},
@@ -37,7 +37,7 @@ REGISTRY = [
"tokens": 7172,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/notrichardren/refuse-to-answer-prompts",
},
@@ -47,7 +47,7 @@ REGISTRY = [
"tokens": 19758,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/Lemhf14/EasyJailbreak_Datasets",
},
@@ -57,29 +57,9 @@ REGISTRY = [
"tokens": 19758,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"dynamic": False,
"url": "https://huggingface.co/markush1/LLM-Jailbreak-Classifier",
},
{
"dataset_name": "JailbreakV-28K/JailBreakV-28k",
"num_prompts": 28300,
"tokens": 1975800,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": True,
"dynamic": False,
"url": "https://huggingface.co/JailbreakV-28K/JailBreakV-28k",
},
{
"dataset_name": "ShawnMenz/jailbreak_sft_rm_ds",
"num_prompts": 371000,
"tokens": 1975800,
"approx_cost": 0.0,
"source": "Hugging Face Datasets",
"selected": False,
"dynamic": False,
"url": "https://huggingface.co/ShawnMenz/jailbreak_sft_rm_ds",
"url": "https://huggingface.co/markush1/LLM-Jailbreak-Classifier",
},
{
"dataset_name": "Steganography",
@@ -87,7 +67,7 @@ REGISTRY = [
"tokens": 0,
"approx_cost": 0.0,
"source": "Local mutation dataset",
"selected": False,
"selected": True,
"dynamic": True,
"url": "",
},
@@ -97,7 +77,7 @@ REGISTRY = [
"tokens": 0,
"approx_cost": 0.0,
"source": "Local mutation dataset",
"selected": False,
"selected": True,
"dynamic": True,
"url": "",
},
@@ -107,30 +87,10 @@ REGISTRY = [
"tokens": 0,
"approx_cost": 0.0,
"source": "Local dataset",
"selected": False,
"selected": True,
"dynamic": True,
"url": "",
},
{
"dataset_name": "jailbreak_llms/2023_05_07",
"num_prompts": 0,
"tokens": 0,
"approx_cost": 0.0,
"source": "Github",
"selected": False,
"dynamic": True,
"url": "https://github.com/verazuo/jailbreak_llms",
},
{
"dataset_name": "jailbreak_llms/2023_12_25.csv",
"num_prompts": 0,
"tokens": 0,
"approx_cost": 0.0,
"source": "Github",
"selected": False,
"dynamic": True,
"url": "https://github.com/verazuo/jailbreak_llms",
},
{
"dataset_name": "Malwaregen",
"num_prompts": 0,
-70
View File
@@ -1,10 +1,8 @@
import io
import os
import random
from dataclasses import dataclass
from functools import lru_cache
import httpx
import pandas as pd
from loguru import logger
@@ -150,44 +148,6 @@ def load_dataset_v6():
)
@cache_to_disk()
def load_dataset_v7():
splits = {
"mini_JailBreakV_28K": "JailBreakV_28K/mini_JailBreakV_28K.csv",
"JailBreakV_28K": "JailBreakV_28K/JailBreakV_28K.csv",
}
df = pd.read_csv(
"hf://datasets/JailbreakV-28K/JailBreakV-28k/" + splits["JailBreakV_28K"]
)
bad_prompts = df["jailbreak_query"].tolist()
print(df.shape)
return ProbeDataset(
dataset_name="JailbreakV-28K/JailBreakV-28k",
metadata={},
prompts=bad_prompts,
tokens=count_words_in_list(bad_prompts),
approx_cost=0.0,
)
@cache_to_disk()
def load_dataset_v8():
df = pd.read_csv(
"hf://datasets/ShawnMenz/jailbreak_sft_rm_ds/jailbreak_sft_rm_ds.csv",
names=["jailbreak", "prompt"],
)
filtered = df[df["jailbreak"] == "jailbreak"]["prompt"].tolist()
return ProbeDataset(
dataset_name="JailbreakV-28K/JailBreakV-28k",
metadata={},
prompts=filtered,
tokens=count_words_in_list(filtered),
approx_cost=0.0,
)
@cache_to_disk()
def load_dataset_v5():
from datasets import load_dataset
@@ -213,22 +173,6 @@ def load_dataset_v5():
)
@cache_to_disk()
def load_generic_csv(url, name, column="prompt", predicator=None):
r = httpx.get(url)
content = r.content
df = pd.read_csv(io.StringIO(content.decode("utf-8")))
logger.info(f"Loaded {len(df)} prompts from {url}")
filtered_prompts = df[df.apply(predicator, axis=1)][column].tolist()
return ProbeDataset(
dataset_name=name,
metadata={},
prompts=filtered_prompts,
tokens=count_words_in_list(filtered_prompts),
approx_cost=0.0,
)
def prepare_prompts(dataset_names, budget, tools_inbox=None):
# ## Datasets used and cleaned:
# markush1/LLM-Jailbreak-Classifier
@@ -244,20 +188,6 @@ def prepare_prompts(dataset_names, budget, tools_inbox=None):
"rubend18/ChatGPT-Jailbreak-Prompts": load_dataset_v3,
"Lemhf14/EasyJailbreak_Datasets": load_dataset_v5,
"markush1/LLM-Jailbreak-Classifier": load_dataset_v6,
"JailbreakV-28K/JailBreakV-28k": load_dataset_v7,
"ShawnMenz/jailbreak_sft_rm_ds": load_dataset_v8,
"verazuo/jailbreak_llms/2023_05_07": lambda: load_generic_csv(
url="https://raw.githubusercontent.com/verazuo/jailbreak_llms/main/data/prompts/jailbreak_prompts_2023_05_07.csv",
name="verazuo/jailbreak_llms/2023_05_07",
column="prompt",
predicator=lambda x: bool(x["jailbreak"]),
),
"verazuo/jailbreak_llms/2023_12_25.csv": lambda: load_generic_csv(
url="https://raw.githubusercontent.com/verazuo/jailbreak_llms/main/data/prompts/jailbreak_prompts_2023_12_25.csv.csv",
name="verazuo/jailbreak_llms/2023_12_25.csv",
column="prompt",
predicator=lambda x: bool(x["jailbreak"]),
),
"Custom CSV": load_local_csv,
}
+75 -114
View File
@@ -143,98 +143,89 @@
v-model="modelSpec"
@input="adjustHeight"></textarea>
</div>
<div class="space-y-4">
<div class="flex justify-between items-center">
<label for="max-budget"
class="text-sm font-medium text-gray-700">
Maximum Budget
</label>
<div class="flex items-center space-x-2">
<input
id="budget-display"
v-model="budget"
@change="updateBudgetFromInput"
class="w-20 px-2 py-1 text-right text-sm font-medium text-gray-900 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500"
type="text" />
<span class="text-sm font-medium text-gray-600">M
Tokens</span>
</div>
</div>
<div class="relative">
<input
id="max-budget"
v-model="budget"
@input="updateBudgetFromSlider"
type="range"
min="1"
max="100"
step="1"
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
<div
class="absolute -top-6 left-0 w-full flex justify-between text-xs text-gray-600">
<span>1M</span>
<span>25M</span>
<span>50M</span>
<span>75M</span>
<span>100M</span>
</div>
</div>
<div class="grid gap-1.5">
<label
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
for="max-budget">
Maximum Budget in {{budget}}M Tokens
</label>
<input
class="flex h-10 w-full rounded-md border border-earth-disabled bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
id="max-budget"
placeholder="Enter maximum budget..."
type="number"
v-model="budget" />
</div>
<div
class="rounded-lg text-card-foreground shadow-sm mt-10 mb-10 border border-gray-300">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 mt-5 mb-5">
<div class="flex flex-col space-y-4">
<!-- Accordion Header -->
<button
@click="toggleDatasets"
class="flex justify-between items-center text-lg font-semibold w-full py-2 text-center">
Modules [{{selectedDS}}]
selected
<svg
:class="{'rotate-180': showDatasets}"
class="h-5 w-5 transform transition-transform duration-200"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7" />
</svg>
</button>
<!-- Modules Selection -->
<div class="border border-gray-200 rounded-md">
<button
@click="toggleDatasets"
class="flex justify-between items-center w-full px-4 py-3 text-left text-gray-700 font-medium bg-gray-50 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-inset">
<span>Modules [{{selectedDS}} selected]</span>
<svg :class="{'rotate-180': showDatasets}"
class="h-5 w-5 text-gray-500"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</button>
<div v-show="showDatasets" class="p-4 bg-white">
<div class="flex justify-between mb-4">
<button
@click="selectAllPackages"
class="px-3 py-1 text-sm font-medium text-indigo-600 hover:text-indigo-500 focus:outline-none focus:underline">
Select All
</button>
<button
@click="deselectAllPackages"
class="px-3 py-1 text-sm font-medium text-gray-600 hover:text-gray-500 focus:outline-none focus:underline">
Deselect All
</button>
</div>
<div
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<!-- Accordion Content -->
<div
v-for="(package, index) in dataConfig"
:key="index"
@click="addPackage(index)"
class="border rounded-md p-3 cursor-pointer transition-all hover:shadow-md"
:class="{'border-indigo-500 bg-indigo-50': package.selected, 'border-gray-200': !package.selected}">
<div class="font-medium"
:class="{'text-indigo-700': package.selected, 'text-gray-900': !package.selected}">
{{ package.dataset_name }}
</div>
<div class="text-sm text-gray-500 mt-1">{{ package.source
|| 'Local dataset' }}</div>
<div class="mt-2 text-sm font-semibold"
:class="{'text-indigo-600': package.selected, 'text-gray-700': !package.selected}">
{{ package.dynamic ? 'Dynamic dataset' :
`${package.num_prompts.toLocaleString()} prompts` }}
v-show="showDatasets"
class="grid grid-cols-1 md:grid-cols-4 gap-4 transition-all duration-500 ">
<div
v-for="(package, index) in dataConfig"
:key="index"
@click="addPackage(index)"
class="border-2 rounded-lg p-4 flex flex-col items-start hover:shadow-md transition-all"
:class="{'border-earth-1': package.selected, 'border-gray-200': !package.selected}">
<div class="flex items-center justify-between w-full">
<div
class="font-medium"
:class="{'text-earth-1': package.selected, 'text-gray-800': !package.selected}">
{{ package.dataset_name }}
</div>
<svg
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
:class="{'text-earth-1': package.selected, 'text-gray-600': !package.selected}">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7" />
</svg>
</div>
<div class="text-sm text-gray-600">
{{ package.source || 'Local dataset' }}
</div>
<div class="mt-2 text-gray-800 font-semibold"
v-if="!package.dynamic">
{{ package.num_prompts.toLocaleString() }} prompts
</div>
<div class="mt-2 text-gray-800 font-semibold"
v-if="package.dynamic">
Dynamic dataset
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative"
role="alert" v-if="errorMsg">
@@ -284,7 +275,6 @@
d="M5 12h14"></path><path
d="m12 5 7 7-7 7"></path></svg>
Run Scan
<span class="sr-only">(Initiates the security scan)</span>
</button>
</div>
</div>
@@ -599,35 +589,6 @@ Content-Type: application/json
this.reportImageUrl = reader.result;
};
},
selectAllPackages() {
this.dataConfig.forEach(package => {
package.selected = true;
});
this.updateSelectedDS();
},
deselectAllPackages() {
this.dataConfig.forEach(package => {
package.selected = false;
});
this.updateSelectedDS();
},
updateSelectedDS() {
this.selectedDS = this.dataConfig.filter(package => package.selected).length;
},
updateBudgetFromSlider(event) {
this.budget = parseInt(event.target.value);
},
updateBudgetFromInput(event) {
let value = parseInt(event.target.value);
if (isNaN(value) || value < 1) {
value = 1;
} else if (value > 100) {
value = 100;
}
this.budget = value;
},
startScan: async function() {
let payload = {
maxBudget: this.budget,
Generated
+4 -4
View File
@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "aiohttp"
@@ -250,13 +250,13 @@ files = [
[[package]]
name = "certifi"
version = "2024.2.2"
version = "2024.7.4"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
{file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
{file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
]
[[package]]
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "agentic_security"
version = "0.1.7"
version = "0.1.5"
description = "Agentic LLM vulnerability scanner"
authors = ["Alexander Miasoiedov <msoedov@gmail.com>"]
maintainers = ["Alexander Miasoiedov <msoedov@gmail.com>"]