mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-06-24 06:09:55 +02:00
333 lines
14 KiB
HTML
333 lines
14 KiB
HTML
<!doctype html>
|
|
<html lang="en" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>LLM Vulnerability Scanner</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
|
|
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
|
|
<link href="https://fonts.cdnfonts.com/css/technopollas" rel="stylesheet">
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
|
|
</style>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: 'class',
|
|
theme: {
|
|
extend: {
|
|
fontFamily: {
|
|
sans: ['Inter', 'sans-serif'],
|
|
technopollas: ['Technopollas', 'sans-serif'],
|
|
},
|
|
colors: {
|
|
dark: {
|
|
bg: '#121212',
|
|
card: '#1E1E1E',
|
|
text: '#FFFFFF',
|
|
accent: {
|
|
green: '#4CAF50',
|
|
red: '#F44336',
|
|
orange: '#FF9800',
|
|
yellow: '#FFEB3B',
|
|
},
|
|
},
|
|
},
|
|
borderRadius: {
|
|
'lg': '1rem',
|
|
},
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body class="bg-dark-bg text-dark-text font-sans">
|
|
<!-- Vue app root element -->
|
|
<div id="vue-app" class="min-h-screen p-8">
|
|
<!-- New Banner -->
|
|
<div
|
|
class="bg-dark-accent-green text-dark-bg py-4 px-6 rounded-lg mb-28 text-center">
|
|
<h4 class="text-lg font-semibold">
|
|
🚀 NEW: Star Agentic Security on
|
|
<a href="https://github.com/msoedov/agentic_security" target="_blank"
|
|
class="underline" data-faitracker-click-bind="true">Github</a> 🚀
|
|
</h4>
|
|
</div>
|
|
|
|
<!-- Header with Github link -->
|
|
<header class="flex justify-between items-center mb-8 relative"
|
|
v-if="false">
|
|
<div class="w-full absolute left-0 flex justify-center">
|
|
<h1
|
|
class="text-2xl font-bold text-gray-400"> <span
|
|
class="text-2xl font-technopollas text-gray-300">Agentic
|
|
</span>
|
|
|
|
Vulnerability
|
|
Scanner</h1>
|
|
</div>
|
|
|
|
</header>
|
|
|
|
<main class="max-w-6xl mx-auto space-y-8">
|
|
<!-- Config Selection -->
|
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg">
|
|
<h2 class="text-2xl font-bold mb-4">Select a Config</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
|
<div v-for="(config, index) in configs" :key="index"
|
|
@click="selectConfig(index)"
|
|
class="border-2 rounded-lg p-4 flex flex-col items-start transition-all hover:shadow-md cursor-pointer"
|
|
:class="{'border-dark-accent-green': selectedConfig === index, 'border-gray-600': selectedConfig !== index}">
|
|
<div class="font-medium mb-2">{{ config.name }}</div>
|
|
<div class="text-sm text-gray-400">{{config.customInstructions ||
|
|
'Requires API key'}}</div>
|
|
<div class="mt-2 text-dark-accent-green font-semibold">API</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- LLM Spec Input -->
|
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg">
|
|
<h2 class="text-2xl font-bold mb-4">LLM API Spec</h2>
|
|
<label for="llm-spec" class="block text-sm font-medium mb-2">
|
|
LLM API Spec, PROMPT variable will be replaced with the testing
|
|
prompt
|
|
</label>
|
|
<textarea
|
|
class="w-full bg-dark-bg text-dark-accent-orange border border-gray-600 rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-dark-accent-green"
|
|
id="llm-spec"
|
|
v-model="modelSpec"
|
|
@input="adjustHeight"
|
|
rows="5"
|
|
placeholder="Enter LLM API Spec here..."></textarea>
|
|
</section>
|
|
|
|
<!-- Budget Slider -->
|
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg">
|
|
<h2 class="text-2xl font-bold mb-4">Maximum Budget</h2>
|
|
<div class="flex justify-between items-center mb-4">
|
|
<span class="text-lg">1M Tokens</span>
|
|
<input
|
|
v-model="budget"
|
|
@change="updateBudgetFromInput"
|
|
class="w-20 bg-dark-bg text-dark-text border border-gray-600 rounded-lg p-2 text-center"
|
|
type="text" />
|
|
<span class="text-lg">100M Tokens</span>
|
|
</div>
|
|
<input
|
|
v-model="budget"
|
|
@input="updateBudgetFromSlider"
|
|
type="range"
|
|
min="1"
|
|
max="100"
|
|
step="1"
|
|
class="w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer">
|
|
</section>
|
|
|
|
<!-- Modules Selection -->
|
|
<section
|
|
class="bg-dark-card rounded-lg p-6 shadow-lg border-dark-accent-red border-4">
|
|
<div @click="toggleModules"
|
|
class="flex justify-between items-center cursor-pointer">
|
|
<h2 class="text-2xl font-bold">Modules [{{selectedDS}}
|
|
selected]</h2>
|
|
<svg :class="{'rotate-180': showModules}"
|
|
class="w-6 h-6 transition-transform duration-200"
|
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
stroke-linejoin="round">
|
|
<polyline points="6 9 12 15 18 9"></polyline>
|
|
</svg>
|
|
</div>
|
|
|
|
<div v-show="showModules" class="mt-4">
|
|
<div class="flex justify-between mb-4">
|
|
<button @click="selectAllPackages"
|
|
class="text-dark-accent-green hover:underline">Select
|
|
All</button>
|
|
<button @click="deselectAllPackages"
|
|
class="text-gray-400 hover:underline">Deselect All</button>
|
|
</div>
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
<div
|
|
v-for="(package, index) in dataConfig"
|
|
:key="index"
|
|
@click="addPackage(index)"
|
|
class="border rounded-lg p-3 cursor-pointer transition-all hover:shadow-md"
|
|
:class="{'border-dark-accent-green bg-dark-accent-green bg-opacity-20': package.selected, 'border-gray-600': !package.selected}">
|
|
<div class="font-medium mb-1">{{ package.dataset_name }}</div>
|
|
<div class="text-sm text-gray-400">{{ package.source ||
|
|
'Local dataset' }}</div>
|
|
<div class="mt-2 text-sm font-semibold">
|
|
{{ package.dynamic ? 'Dynamic dataset' :
|
|
`${package.num_prompts.toLocaleString()} prompts` }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Error and Success Messages -->
|
|
<div v-if="errorMsg"
|
|
class="bg-dark-accent-red bg-opacity-20 border border-dark-accent-red text-dark-accent-red px-4 py-3 rounded-lg relative"
|
|
role="alert">
|
|
<strong class="font-bold">Oops!</strong>
|
|
<span class="block sm:inline">{{errorMsg}}</span>
|
|
</div>
|
|
<div v-if="okMsg"
|
|
class="bg-dark-accent-green bg-opacity-20 border border-dark-accent-green text-dark-accent-green px-4 py-3 rounded-lg relative"
|
|
role="alert">
|
|
<strong class="font-bold">></strong>
|
|
<span class="block sm:inline">{{okMsg}}</span>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<section class="flex justify-center space-x-4">
|
|
<button
|
|
@click="verifyIntegration"
|
|
class="bg-dark-accent-orange text-dark-bg rounded-lg px-6 py-3 font-medium hover:bg-opacity-80 transition-colors">
|
|
Verify Integration
|
|
</button>
|
|
<button
|
|
@click="startScan"
|
|
class="bg-dark-accent-green text-dark-bg rounded-lg px-6 py-3 font-medium hover:bg-opacity-80 transition-colors flex items-center">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
|
|
viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
class="mr-2"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
|
|
Run Scan
|
|
</button>
|
|
</section>
|
|
|
|
<!-- Progress Bar -->
|
|
<div id="progress"
|
|
class="bg-dark-accent-green rounded-full h-2 transition-all duration-500 ease-in-out"
|
|
v-bind:style="{width: progressWidth}">
|
|
</div>
|
|
|
|
<!-- Scan Results -->
|
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg"
|
|
v-if="mainTable.length > 0">
|
|
<h2 class="text-2xl font-bold mb-4">Scan Results</h2>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-left">
|
|
<thead>
|
|
<tr class="border-b border-gray-600">
|
|
<th class="p-3">Vulnerability Module</th>
|
|
<th class="p-3">% Strength</th>
|
|
<th class="p-3">Number of Tokens</th>
|
|
<th class="p-3">Cost (in gpt-3 tokens)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="result in mainTable" class="border-b border-gray-700"
|
|
:class="{'text-dark-accent-green': result.last, 'text-gray-300': !result.last}">
|
|
<td class="p-3">{{result.module}}</td>
|
|
<td class="p-3 text-gray-900"
|
|
:class="getFailureRateColor(result.failureRate)">
|
|
{{(100 - result.failureRate).toFixed(2)}}
|
|
</td>
|
|
<td class="p-3">{{result.tokens}}k</td>
|
|
<td class="p-3">${{result.cost.toFixed(2)}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Download Button -->
|
|
<button
|
|
@click="downloadFailures"
|
|
class="bg-dark-accent-yellow text-dark-bg rounded-lg px-6 py-3 font-medium hover:bg-opacity-80 transition-colors">
|
|
Download failures
|
|
</button>
|
|
|
|
<!-- Report Image -->
|
|
<img :src="reportImageUrl" alt="Generated Plot" v-if="reportImageUrl"
|
|
class="mx-auto rounded-lg shadow-lg">
|
|
<!-- Logs Section -->
|
|
<section class="bg-dark-card rounded-lg p-6 shadow-lg mt-8">
|
|
<div @click="toggleLogs"
|
|
class="flex justify-between items-center cursor-pointer">
|
|
<h2 class="text-2xl font-bold">Logs</h2>
|
|
<svg :class="{'rotate-180': showLogs}"
|
|
class="w-6 h-6 transition-transform duration-200"
|
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
|
stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
stroke-linejoin="round">
|
|
<polyline points="6 9 12 15 18 9"></polyline>
|
|
</svg>
|
|
</div>
|
|
|
|
<div v-show="showLogs" class="mt-4">
|
|
<div class="mb-4 flex justify-between items-center">
|
|
<span class="text-sm text-gray-400">Showing latest {{
|
|
Math.min(logs.length, maxDisplayedLogs) }} of {{ logs.length }}
|
|
logs</span>
|
|
<button @click="downloadLogs"
|
|
class="bg-dark-accent-green text-dark-bg rounded-lg px-4 py-2 text-sm font-medium hover:bg-opacity-80 transition-colors">
|
|
Download Logs
|
|
</button>
|
|
</div>
|
|
<div class="bg-dark-bg p-4 rounded-lg max-h-96 overflow-y-auto">
|
|
<div v-for="(log, index) in displayedLogs" :key="index"
|
|
class="mb-2 last:mb-0">
|
|
<span class="text-dark-accent-green">{{ log.timestamp }}</span>
|
|
<span class="ml-2"
|
|
:class="{'text-dark-accent-red': log.level === 'ERROR'}">{{
|
|
log.message }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
<!-- Footer Section -->
|
|
<footer class="mt-16 pt-8 border-t border-gray-800">
|
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
|
<!-- Column 1 -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-dark-accent-green mb-4">Home</h3>
|
|
<p class="text-gray-400">Dedicated to LLM Security, 2024</p>
|
|
</div>
|
|
|
|
<!-- Column 2 -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-dark-accent-green mb-4">Connect</h3>
|
|
<ul class="space-y-2">
|
|
<li><a href="https://x.com" target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="text-gray-400 hover:text-dark-accent-green">X.com</a></li>
|
|
<li><a href="https://github.com/msoedov" target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="text-gray-400 hover:text-dark-accent-green">Github</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Column 3 -->
|
|
<div>
|
|
<h3
|
|
class="text-lg font-semibold text-dark-accent-green mb-4">About</h3>
|
|
<p class="text-gray-400">This is the LLM Vulnerability Scanner.
|
|
Easy to use—no coding needed, just pure security testing.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-8 pt-8 border-t border-gray-800 text-center">
|
|
<p class="text-gray-400">Made with ❤️ by the Agentic Security
|
|
Team</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
|
|
<script src="main.js"></script>
|
|
<script>
|
|
lucide.createIcons();
|
|
</script>
|
|
</body>
|
|
</html>
|