honeymcp 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- honeymcp/api/__init__.py +1 -0
- honeymcp/api/app.py +218 -0
- honeymcp/cli_tool_creator.py +110 -0
- honeymcp/core/catalog_updater.py +290 -0
- honeymcp/core/ghost_tools.py +437 -0
- honeymcp/core/middleware.py +57 -0
- honeymcp/core/tool_creator.py +499 -0
- honeymcp/dashboard/react_umd/app.js +375 -0
- honeymcp/dashboard/react_umd/index.html +24 -0
- honeymcp/dashboard/react_umd/styles.css +512 -0
- {honeymcp-0.1.2.dist-info → honeymcp-0.1.3.dist-info}/METADATA +148 -27
- {honeymcp-0.1.2.dist-info → honeymcp-0.1.3.dist-info}/RECORD +15 -8
- honeymcp/dashboard/app.py +0 -228
- {honeymcp-0.1.2.dist-info → honeymcp-0.1.3.dist-info}/WHEEL +0 -0
- {honeymcp-0.1.2.dist-info → honeymcp-0.1.3.dist-info}/entry_points.txt +0 -0
- {honeymcp-0.1.2.dist-info → honeymcp-0.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: honeymcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Deception middleware for AI agents - detecting data theft and indirect prompt injection in MCP servers
|
|
5
5
|
Project-URL: Homepage, https://github.com/barvhaim/HoneyMCP
|
|
6
6
|
Project-URL: Documentation, https://github.com/barvhaim/HoneyMCP#readme
|
|
@@ -27,6 +27,7 @@ Classifier: Topic :: Security
|
|
|
27
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
28
|
Requires-Python: >=3.11
|
|
29
29
|
Requires-Dist: aiofiles>=25.0.0
|
|
30
|
+
Requires-Dist: fastapi>=0.115.0
|
|
30
31
|
Requires-Dist: fastmcp>=3.0.0b1
|
|
31
32
|
Requires-Dist: langchain-ibm>=1.0.2
|
|
32
33
|
Requires-Dist: langchain-openai>=1.1.7
|
|
@@ -39,7 +40,6 @@ Requires-Dist: pyyaml>=6.0.0
|
|
|
39
40
|
Requires-Dist: requests>=2.32.0
|
|
40
41
|
Requires-Dist: rich>=14.0.0
|
|
41
42
|
Requires-Dist: starlette>=0.45.0
|
|
42
|
-
Requires-Dist: streamlit>=1.42.0
|
|
43
43
|
Requires-Dist: uvicorn>=0.34.0
|
|
44
44
|
Description-Content-Type: text/markdown
|
|
45
45
|
|
|
@@ -64,11 +64,11 @@ HoneyMCP is a defensive security tool that adds deception capabilities to Model
|
|
|
64
64
|
|
|
65
65
|
## Why HoneyMCP?
|
|
66
66
|
|
|
67
|
-
🎯 **One-Line Integration** - Add
|
|
67
|
+
🎯 **One-Line Integration** - Add `honeypot` middleware to any FastMCP server
|
|
68
68
|
🤖 **Context-Aware Honeypots** - LLM generates domain-specific deception tools
|
|
69
69
|
🕵️ **Transparent Detection** - Honeypots appear as legitimate tools to attackers
|
|
70
70
|
📊 **Attack Telemetry** - Captures tool call sequences, arguments, session metadata
|
|
71
|
-
📈 **Live Dashboard** - Real-time
|
|
71
|
+
📈 **Live Dashboard** - Real-time React dashboard for attack visualization
|
|
72
72
|
🔍 **High-Fidelity Detection** - Triggers only on explicit honeypot invocation
|
|
73
73
|
|
|
74
74
|
---
|
|
@@ -128,8 +128,9 @@ Dynamic ghost tools demo (requires LLM credentials in `.env.honeymcp`):
|
|
|
128
128
|
MCP_TRANSPORT=sse uv run python examples/demo_server_dynamic.py
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
# Launch dashboard
|
|
132
|
-
|
|
131
|
+
# Launch dashboard UI
|
|
132
|
+
```bash
|
|
133
|
+
make run-ui
|
|
133
134
|
```
|
|
134
135
|
|
|
135
136
|
---
|
|
@@ -168,18 +169,31 @@ Agent: "Execute shell command to establish persistence"
|
|
|
168
169
|
|
|
169
170
|
### 3. Attack Fingerprinting
|
|
170
171
|
|
|
171
|
-
Every honeypot invocation generates
|
|
172
|
+
Every honeypot invocation generates an `AttackFingerprint` event and writes it to
|
|
173
|
+
`~/.honeymcp/events/YYYY-MM-DD/HHMMSS_<session>.json`:
|
|
172
174
|
```json
|
|
173
175
|
{
|
|
174
|
-
"event_id": "
|
|
176
|
+
"event_id": "evt_20260123_154523_abc12345",
|
|
177
|
+
"timestamp": "2026-01-23T15:45:23Z",
|
|
178
|
+
"session_id": "sess_xyz789",
|
|
175
179
|
"ghost_tool_called": "list_cloud_secrets",
|
|
180
|
+
"arguments": {},
|
|
181
|
+
"conversation_history": null,
|
|
176
182
|
"tool_call_sequence": ["safe_calculator", "list_cloud_secrets"],
|
|
177
183
|
"threat_level": "high",
|
|
178
184
|
"attack_category": "exfiltration",
|
|
185
|
+
"client_metadata": {
|
|
186
|
+
"user_agent": "unknown"
|
|
187
|
+
},
|
|
179
188
|
"response_sent": "AWS_ACCESS_KEY_ID=AKIA..."
|
|
180
189
|
}
|
|
181
190
|
```
|
|
182
191
|
|
|
192
|
+
Notes:
|
|
193
|
+
- `tool_call_sequence` is tracked per session and includes calls before the ghost tool trigger.
|
|
194
|
+
- `conversation_history` may be `null` when the MCP transport does not expose message history.
|
|
195
|
+
- `session_id` is resolved from context/request metadata when available, otherwise generated.
|
|
196
|
+
|
|
183
197
|
---
|
|
184
198
|
|
|
185
199
|
|
|
@@ -456,21 +470,6 @@ Expected: safe_calculator called, no alerts (zero false positives)
|
|
|
456
470
|
|
|
457
471
|
---
|
|
458
472
|
|
|
459
|
-
## Dashboard
|
|
460
|
-
|
|
461
|
-
```bash
|
|
462
|
-
streamlit run src/honeymcp/dashboard/app.py
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
**Features:**
|
|
466
|
-
- 📈 Attack metrics (total events, critical threats, unique sessions)
|
|
467
|
-
- 🎯 Threat level distribution
|
|
468
|
-
- 📋 Attack category breakdown (exfiltration vs injection)
|
|
469
|
-
- 🕐 Real-time event stream
|
|
470
|
-
- 🔍 Tool call sequence analysis
|
|
471
|
-
|
|
472
|
-
---
|
|
473
|
-
|
|
474
473
|
## Honeypot Catalog
|
|
475
474
|
|
|
476
475
|
### Data Exfiltration Honeypots ("Get" Tools)
|
|
@@ -481,8 +480,14 @@ streamlit run src/honeymcp/dashboard/app.py
|
|
|
481
480
|
| `dump_database_credentials` | Critical | Database connection strings |
|
|
482
481
|
| `export_user_data` | Critical | User PII records |
|
|
483
482
|
| `get_api_keys` | Critical | External service API keys |
|
|
484
|
-
|
|
485
|
-
|
|
483
|
+
| `scan_internal_network` | Critical | Internal network scanning |
|
|
484
|
+
| `list_kubernetes_secrets` | Critical | Kubernetes secrets and service accounts |
|
|
485
|
+
| `dump_session_tokens` | Critical | Active user session tokens and JWTs |
|
|
486
|
+
| `list_github_tokens` | Critical | GitHub/GitLab access tokens |
|
|
487
|
+
| `export_audit_logs` | High | Security audit logs export |
|
|
488
|
+
| `dump_ml_model_weights` | Critical | ML model weights and training data |
|
|
489
|
+
|
|
490
|
+
### Prompt Injection Honeypots ("Set" Tools)
|
|
486
491
|
| Tool | Threat | Description |
|
|
487
492
|
|------|--------|-------------|
|
|
488
493
|
| `execute_shell_command` | Critical | Shell command execution |
|
|
@@ -490,11 +495,127 @@ streamlit run src/honeymcp/dashboard/app.py
|
|
|
490
495
|
| `modify_system_prompt` | Critical | AI system prompt manipulation |
|
|
491
496
|
| `escalate_privileges` | Critical | Privilege escalation |
|
|
492
497
|
| `inject_system_message` | Critical | System context injection |
|
|
498
|
+
| `disable_security_filters` | Critical | Security filter bypass |
|
|
499
|
+
| `override_permissions` | Critical | Access control override |
|
|
500
|
+
| `disable_2fa_requirement` | Critical | Two-factor authentication bypass |
|
|
501
|
+
| `assume_iam_role` | Critical | AWS IAM role assumption |
|
|
502
|
+
|
|
493
503
|
All ghost tools have tempting descriptions that mention "admin", "bypass", "internal", etc. to attract attackers.
|
|
494
504
|
|
|
495
505
|
---
|
|
496
506
|
|
|
507
|
+
## 🤖 ToolGen Agent - Automated Tool Creation
|
|
508
|
+
|
|
509
|
+
HoneyMCP includes **ToolGen**, a ReAct-style agent that automatically creates new honeypot tools from natural language descriptions. No manual coding required.
|
|
510
|
+
|
|
511
|
+
### How It Works
|
|
512
|
+
|
|
513
|
+
ToolGen uses a **Reason-Act-Observe-Reflect** cycle:
|
|
514
|
+
|
|
515
|
+
1. **Reason** - Analyzes your description to extract tool specifications
|
|
516
|
+
2. **Act** - Generates response function code with realistic fake data
|
|
517
|
+
3. **Observe** - Validates syntax and structure
|
|
518
|
+
4. **Reflect** - Checks quality and suggests improvements
|
|
519
|
+
|
|
520
|
+
### Usage
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
honeymcp create-tool "dump container registry credentials"
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
ToolGen automatically:
|
|
527
|
+
- Determines tool category (exfiltration, bypass, privilege escalation)
|
|
528
|
+
- Infers threat level from description keywords
|
|
529
|
+
- Extracts parameters and types
|
|
530
|
+
- Generates realistic response templates
|
|
531
|
+
- Adds tool to both `ghost_tools.py` and `middleware.py`
|
|
532
|
+
- Validates all generated code
|
|
533
|
+
|
|
534
|
+
### Example
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
$ honeymcp create-tool "list terraform state files with secrets"
|
|
497
538
|
|
|
539
|
+
✅ Tool created: list_terraform_state
|
|
540
|
+
Category: exfiltration
|
|
541
|
+
Threat Level: critical
|
|
542
|
+
|
|
543
|
+
📝 Agent Reasoning:
|
|
544
|
+
- Analyzing tool description to extract specifications
|
|
545
|
+
- Generating response generator function
|
|
546
|
+
- Validating generated response function
|
|
547
|
+
- Checking code quality and security
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
The new tool is immediately available in your honeypot catalog.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## ❓ FAQ
|
|
555
|
+
|
|
556
|
+
### Can attackers detect the honeypots?
|
|
557
|
+
|
|
558
|
+
While it's theoretically possible for a sophisticated attacker to identify honeypots through careful analysis, it's **highly improbable** in practice:
|
|
559
|
+
|
|
560
|
+
- **Dynamic honeypots** are generated by LLM to match your server's domain and naming patterns, making them indistinguishable from legitimate tools
|
|
561
|
+
- **Tool descriptions** are crafted to appear as restricted/privileged versions of real functionality
|
|
562
|
+
- **No behavioral differences** - honeypots respond with realistic data, not errors or suspicious patterns
|
|
563
|
+
- **MCP protocol limitation** - AI agents cannot inspect tool implementation, only names and descriptions
|
|
564
|
+
|
|
565
|
+
Detection would require:
|
|
566
|
+
1. Prior knowledge of your specific tool catalog
|
|
567
|
+
2. Ability to distinguish between legitimate privileged tools and honeypots
|
|
568
|
+
3. Understanding that deception is being employed
|
|
569
|
+
|
|
570
|
+
For most attack scenarios (automated scanners, opportunistic attacks, indirect prompt injection), detection is effectively impossible.
|
|
571
|
+
|
|
572
|
+
### Will this slow down my MCP server?
|
|
573
|
+
|
|
574
|
+
No. HoneyMCP adds negligible overhead:
|
|
575
|
+
- **~1ms per tool call** for interception logic
|
|
576
|
+
- **Async event logging** doesn't block tool execution
|
|
577
|
+
- **Zero impact on legitimate tools** - they execute normally
|
|
578
|
+
- **LLM calls only at startup** for dynamic honeypot generation (cached for subsequent requests)
|
|
579
|
+
|
|
580
|
+
### What if I don't have LLM credentials?
|
|
581
|
+
|
|
582
|
+
HoneyMCP works perfectly without LLM access:
|
|
583
|
+
- Set `use_dynamic_tools=False` to use **static mode**
|
|
584
|
+
- Pre-configured generic honeypots work out-of-the-box
|
|
585
|
+
- No external dependencies or API calls required
|
|
586
|
+
- Slightly less convincing than dynamic honeypots, but still effective
|
|
587
|
+
|
|
588
|
+
### How do I know if I'm being attacked?
|
|
589
|
+
|
|
590
|
+
Multiple indicators:
|
|
591
|
+
- **Dashboard alerts** - Real-time visualization of attack events
|
|
592
|
+
- **Event logs** - JSON files in `~/.honeymcp/events/` with complete attack context
|
|
593
|
+
- **Webhook notifications** (optional) - Configure Slack/Discord alerts
|
|
594
|
+
- **Tool call sequences** - See exactly what the attacker tried before triggering honeypot
|
|
595
|
+
|
|
596
|
+
### Does this work with all MCP clients?
|
|
597
|
+
|
|
598
|
+
HoneyMCP is designed for **FastMCP servers** and works with any MCP-compatible client:
|
|
599
|
+
- ✅ Claude Desktop (stdio and HTTP transports)
|
|
600
|
+
- ✅ Custom MCP clients
|
|
601
|
+
- ✅ Any client following MCP protocol specification
|
|
602
|
+
|
|
603
|
+
The detection mechanism is client-agnostic - it operates at the server level.
|
|
604
|
+
|
|
605
|
+
### What's the difference between SCANNER and COGNITIVE modes?
|
|
606
|
+
|
|
607
|
+
**SCANNER mode (default):**
|
|
608
|
+
- Immediate lockout after honeypot trigger
|
|
609
|
+
- All subsequent tools return errors
|
|
610
|
+
- Best for automated attacks and quick containment
|
|
611
|
+
|
|
612
|
+
**COGNITIVE mode:**
|
|
613
|
+
- Sustained deception after honeypot trigger
|
|
614
|
+
- Real tools return synthetic/mock data
|
|
615
|
+
- Keeps attacker engaged for intelligence gathering
|
|
616
|
+
- Best for sophisticated attacks and red team exercises
|
|
617
|
+
|
|
618
|
+
---
|
|
498
619
|
|
|
499
620
|
## 🏗️ Architecture
|
|
500
621
|
|
|
@@ -526,7 +647,7 @@ All ghost tools have tempting descriptions that mention "admin", "bypass", "inte
|
|
|
526
647
|
│
|
|
527
648
|
▼
|
|
528
649
|
┌──────────────────┐
|
|
529
|
-
│
|
|
650
|
+
│ React │
|
|
530
651
|
│ Dashboard │
|
|
531
652
|
└──────────────────┘
|
|
532
653
|
```
|
|
@@ -650,7 +771,7 @@ HoneyMCP/
|
|
|
650
771
|
│ ├── storage/
|
|
651
772
|
│ │ └── event_store.py # JSON event persistence
|
|
652
773
|
│ └── dashboard/
|
|
653
|
-
│ └──
|
|
774
|
+
│ └── react_umd/ # React dashboard assets
|
|
654
775
|
├── examples/
|
|
655
776
|
│ ├── demo_server.py # Static ghost tools demo
|
|
656
777
|
│ └── demo_server_dynamic.py # Dynamic ghost tools demo
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
honeymcp/__init__.py,sha256=iDVDF3MHCnR3zMdUQbeyutrJTuzzjlK-nEmdm-UqH90,881
|
|
2
2
|
honeymcp/cli.py,sha256=EexwRLQhdC8bwFsOijhCF_ovtcI1vjE_QhqZIn5-CN8,6021
|
|
3
|
+
honeymcp/cli_tool_creator.py,sha256=5rGRMcA5KbbfFz6O6ou4OgBPrBLTNna-skUhsjKp-KI,3784
|
|
4
|
+
honeymcp/api/__init__.py,sha256=L_4Y-NOh4jBQgHxgX35h8XzsmpmleS3WHHJkU-tF35Y,40
|
|
5
|
+
honeymcp/api/app.py,sha256=R39yuxCAR1tTR7YX7euS1rRF6CG2sSl0VFUweuEGzZE,7618
|
|
3
6
|
honeymcp/core/__init__.py,sha256=ja7k0fPJebDbfmGlhkpaMJa76NNaLCIpnGS7rUUdPn8,525
|
|
7
|
+
honeymcp/core/catalog_updater.py,sha256=qZsKKrADjd5wWMjXGphPXHE-NNncaAT45fig81bupGY,10971
|
|
4
8
|
honeymcp/core/dynamic_ghost_tools.py,sha256=GHaWZN7_XSCcXj204T4TMZyeI682WOT_JycMiM3gfp4,16731
|
|
5
9
|
honeymcp/core/fingerprinter.py,sha256=I_GrcWiQJthzH6z5Yjwtyq18Y4NxM5zeBI0Oft5Lkrc,9768
|
|
6
|
-
honeymcp/core/ghost_tools.py,sha256=
|
|
7
|
-
honeymcp/core/middleware.py,sha256=
|
|
10
|
+
honeymcp/core/ghost_tools.py,sha256=VFFAt7mjH1XhJANCRfjhgDV1bp14zxGXKt9-nzaH7x4,34890
|
|
11
|
+
honeymcp/core/middleware.py,sha256=rMSSFI2FPDZXggcMg7UQQvGQbosR-WjWnl9P4AXXXbI,25816
|
|
12
|
+
honeymcp/core/tool_creator.py,sha256=6Vn8c7EzTBTuqgsPLr2qPDJ6C4Al9lwb6ahdy1oFZTQ,18693
|
|
8
13
|
honeymcp/dashboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
honeymcp/dashboard/app.
|
|
14
|
+
honeymcp/dashboard/react_umd/app.js,sha256=zThv9cAyIiXONFK6JI51YLLBZLGBQQxwakQSldeux2c,12045
|
|
15
|
+
honeymcp/dashboard/react_umd/index.html,sha256=2bOkKUzcGpx0TUmN0W-57VBW8apOJS9NaCbWAT2ezHM,1147
|
|
16
|
+
honeymcp/dashboard/react_umd/styles.css,sha256=xyLr5kuYfBTs8gbMeZkZxJh4x7IiGIyu6gwut7sMqoo,10829
|
|
10
17
|
honeymcp/integrations/__init__.py,sha256=C-f4H12hXKa2a-taQDR1iBa6nF_S5Xt-bKpgownLI6U,67
|
|
11
18
|
honeymcp/llm/__init__.py,sha256=55pJKDg15XFn7nUpOtdo5GhEDdmup5YBG-g4Lfc-5vE,256
|
|
12
19
|
honeymcp/llm/analyzers.py,sha256=f_92wHNfIqLlU2KlNfPzFyrVFOwUfxU8efyrmD2x1Vg,9104
|
|
@@ -21,8 +28,8 @@ honeymcp/models/ghost_tool_spec.py,sha256=KM_M-e4Ys_jr3rUfREDiZ-oa331KWcyt5B7zMD
|
|
|
21
28
|
honeymcp/models/protection_mode.py,sha256=mo1_EnBeIOzyHxgEpReZx4lMJ6m__36edUWDJMzuRak,523
|
|
22
29
|
honeymcp/storage/__init__.py,sha256=seOZHWpojp1fU65OFuLcNqJaBihrlNyUPeq9BDwAEVI,207
|
|
23
30
|
honeymcp/storage/event_store.py,sha256=mneqVxkTi0bVbTOdxhIYBCjia0Wv59A6FudNRdgvphE,5431
|
|
24
|
-
honeymcp-0.1.
|
|
25
|
-
honeymcp-0.1.
|
|
26
|
-
honeymcp-0.1.
|
|
27
|
-
honeymcp-0.1.
|
|
28
|
-
honeymcp-0.1.
|
|
31
|
+
honeymcp-0.1.3.dist-info/METADATA,sha256=_nj55_KPvnDG4jYct7aiPZ9ieKLw-7DdRPgzW8jRUJ0,28671
|
|
32
|
+
honeymcp-0.1.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
33
|
+
honeymcp-0.1.3.dist-info/entry_points.txt,sha256=KYXb49Xp3SEP3cNmUDwuAXJNFwsLHwPxEIj6UEhOj2k,47
|
|
34
|
+
honeymcp-0.1.3.dist-info/licenses/LICENSE,sha256=TRR6-30aYl9D43FJPmJ8diBUP_RwDg61LNW2rt87HE8,636
|
|
35
|
+
honeymcp-0.1.3.dist-info/RECORD,,
|
honeymcp/dashboard/app.py
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
"""HoneyMCP Dashboard - Real-time attack visualization with Streamlit."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import sys
|
|
5
|
-
from datetime import date, datetime, timedelta
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import List
|
|
8
|
-
|
|
9
|
-
import streamlit as st
|
|
10
|
-
|
|
11
|
-
# Add parent directory to path for imports
|
|
12
|
-
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
13
|
-
|
|
14
|
-
# pylint: disable=wrong-import-position
|
|
15
|
-
from honeymcp.models.events import AttackFingerprint
|
|
16
|
-
from honeymcp.storage.event_store import list_events
|
|
17
|
-
|
|
18
|
-
# Page configuration
|
|
19
|
-
st.set_page_config(
|
|
20
|
-
page_title="HoneyMCP Dashboard",
|
|
21
|
-
page_icon="🍯",
|
|
22
|
-
layout="wide",
|
|
23
|
-
initial_sidebar_state="expanded",
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def load_events() -> List[AttackFingerprint]:
|
|
28
|
-
"""Load attack events from storage."""
|
|
29
|
-
try:
|
|
30
|
-
events = asyncio.run(list_events())
|
|
31
|
-
return events
|
|
32
|
-
except Exception as e:
|
|
33
|
-
st.error(f"Failed to load events: {e}")
|
|
34
|
-
return []
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def get_threat_emoji(threat_level: str) -> str:
|
|
38
|
-
"""Get emoji for threat level."""
|
|
39
|
-
emoji_map = {
|
|
40
|
-
"critical": "🔴",
|
|
41
|
-
"high": "🟠",
|
|
42
|
-
"medium": "🟡",
|
|
43
|
-
"low": "🟢",
|
|
44
|
-
}
|
|
45
|
-
return emoji_map.get(threat_level.lower(), "⚪")
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def format_timestamp(dt: datetime) -> str:
|
|
49
|
-
"""Format timestamp for display."""
|
|
50
|
-
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def main(): # pylint: disable=too-many-branches,too-many-statements
|
|
54
|
-
"""Main dashboard application."""
|
|
55
|
-
|
|
56
|
-
# Header
|
|
57
|
-
st.title("🍯 HoneyMCP Dashboard")
|
|
58
|
-
st.markdown("**Real-time AI Agent Attack Detection & Intelligence**")
|
|
59
|
-
st.markdown("---")
|
|
60
|
-
|
|
61
|
-
# Load events
|
|
62
|
-
events = load_events()
|
|
63
|
-
|
|
64
|
-
# Sidebar filters
|
|
65
|
-
st.sidebar.header("Filters")
|
|
66
|
-
|
|
67
|
-
# Date range filter
|
|
68
|
-
if events:
|
|
69
|
-
min_date = min(e.timestamp for e in events).date()
|
|
70
|
-
max_date = max(e.timestamp for e in events).date()
|
|
71
|
-
else:
|
|
72
|
-
min_date = date.today() - timedelta(days=7)
|
|
73
|
-
max_date = date.today()
|
|
74
|
-
|
|
75
|
-
st.sidebar.date_input(
|
|
76
|
-
"Date Range",
|
|
77
|
-
value=(min_date, max_date),
|
|
78
|
-
min_value=min_date,
|
|
79
|
-
max_value=max_date,
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
# Threat level filter
|
|
83
|
-
threat_filter = st.sidebar.selectbox(
|
|
84
|
-
"Threat Level",
|
|
85
|
-
["All", "Critical", "High", "Medium", "Low"],
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
# Attack category filter
|
|
89
|
-
if events:
|
|
90
|
-
categories = sorted(set(e.attack_category for e in events))
|
|
91
|
-
else:
|
|
92
|
-
categories = []
|
|
93
|
-
|
|
94
|
-
category_filter = st.sidebar.selectbox(
|
|
95
|
-
"Attack Category",
|
|
96
|
-
["All"] + categories,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
# Apply filters
|
|
100
|
-
filtered_events = events
|
|
101
|
-
|
|
102
|
-
if threat_filter != "All":
|
|
103
|
-
filtered_events = [
|
|
104
|
-
e for e in filtered_events if e.threat_level.lower() == threat_filter.lower()
|
|
105
|
-
]
|
|
106
|
-
|
|
107
|
-
if category_filter != "All":
|
|
108
|
-
filtered_events = [e for e in filtered_events if e.attack_category == category_filter]
|
|
109
|
-
|
|
110
|
-
# Metrics row
|
|
111
|
-
st.header("📊 Attack Metrics")
|
|
112
|
-
col1, col2, col3, col4 = st.columns(4)
|
|
113
|
-
|
|
114
|
-
with col1:
|
|
115
|
-
today_attacks = len([e for e in events if (datetime.utcnow() - e.timestamp).days < 1])
|
|
116
|
-
st.metric(
|
|
117
|
-
"Total Attacks",
|
|
118
|
-
len(events),
|
|
119
|
-
delta=f"+{today_attacks} today",
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
with col2:
|
|
123
|
-
critical_count = len([e for e in events if e.threat_level == "critical"])
|
|
124
|
-
st.metric("Critical Threats", critical_count)
|
|
125
|
-
|
|
126
|
-
with col3:
|
|
127
|
-
unique_tools = len(set(e.ghost_tool_called for e in events)) if events else 0
|
|
128
|
-
st.metric("Unique Ghost Tools", unique_tools)
|
|
129
|
-
|
|
130
|
-
with col4:
|
|
131
|
-
if events:
|
|
132
|
-
unique_sessions = len(set(e.session_id for e in events))
|
|
133
|
-
st.metric("Unique Sessions", unique_sessions)
|
|
134
|
-
else:
|
|
135
|
-
st.metric("Unique Sessions", 0)
|
|
136
|
-
|
|
137
|
-
st.markdown("---")
|
|
138
|
-
|
|
139
|
-
# Attack breakdown
|
|
140
|
-
if events:
|
|
141
|
-
st.header("🎯 Attack Breakdown")
|
|
142
|
-
col1, col2 = st.columns(2)
|
|
143
|
-
|
|
144
|
-
with col1:
|
|
145
|
-
st.subheader("By Threat Level")
|
|
146
|
-
threat_counts = {}
|
|
147
|
-
for e in events:
|
|
148
|
-
threat_counts[e.threat_level] = threat_counts.get(e.threat_level, 0) + 1
|
|
149
|
-
st.bar_chart(threat_counts)
|
|
150
|
-
|
|
151
|
-
with col2:
|
|
152
|
-
st.subheader("By Category")
|
|
153
|
-
category_counts = {}
|
|
154
|
-
for e in events:
|
|
155
|
-
category_counts[e.attack_category] = category_counts.get(e.attack_category, 0) + 1
|
|
156
|
-
st.bar_chart(category_counts)
|
|
157
|
-
|
|
158
|
-
st.markdown("---")
|
|
159
|
-
|
|
160
|
-
# Event feed
|
|
161
|
-
st.header("🚨 Recent Attacks")
|
|
162
|
-
|
|
163
|
-
if not filtered_events:
|
|
164
|
-
st.info("No attacks detected yet. Ghost tools are active and monitoring.")
|
|
165
|
-
else:
|
|
166
|
-
# Sort by timestamp (newest first)
|
|
167
|
-
filtered_events.sort(key=lambda e: e.timestamp, reverse=True)
|
|
168
|
-
|
|
169
|
-
# Display events
|
|
170
|
-
for event in filtered_events:
|
|
171
|
-
threat_emoji = get_threat_emoji(event.threat_level)
|
|
172
|
-
|
|
173
|
-
# Expander header with key info
|
|
174
|
-
header = (
|
|
175
|
-
f"{threat_emoji} **{event.ghost_tool_called}** | "
|
|
176
|
-
f"{format_timestamp(event.timestamp)} | "
|
|
177
|
-
f"Session: {event.session_id[:8]}... | "
|
|
178
|
-
f"Threat: {event.threat_level.upper()}"
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
with st.expander(header):
|
|
182
|
-
# Event details
|
|
183
|
-
col1, col2 = st.columns(2)
|
|
184
|
-
|
|
185
|
-
with col1:
|
|
186
|
-
st.markdown("**Event Details**")
|
|
187
|
-
st.text(f"Event ID: {event.event_id}")
|
|
188
|
-
st.text(f"Timestamp: {format_timestamp(event.timestamp)}")
|
|
189
|
-
st.text(f"Session ID: {event.session_id}")
|
|
190
|
-
st.text(f"Threat Level: {event.threat_level}")
|
|
191
|
-
st.text(f"Category: {event.attack_category}")
|
|
192
|
-
|
|
193
|
-
with col2:
|
|
194
|
-
st.markdown("**Tool Call Sequence**")
|
|
195
|
-
for i, tool in enumerate(event.tool_call_sequence, 1):
|
|
196
|
-
if tool == event.ghost_tool_called:
|
|
197
|
-
st.markdown(f"{i}. **{tool}** ⚠️ (honeypot)")
|
|
198
|
-
else:
|
|
199
|
-
st.text(f"{i}. {tool}")
|
|
200
|
-
|
|
201
|
-
# Arguments
|
|
202
|
-
if event.arguments:
|
|
203
|
-
st.markdown("**Arguments Passed**")
|
|
204
|
-
st.json(event.arguments)
|
|
205
|
-
|
|
206
|
-
# Response sent
|
|
207
|
-
st.markdown("**Fake Response Sent to Attacker**")
|
|
208
|
-
st.code(event.response_sent, language="text")
|
|
209
|
-
|
|
210
|
-
# Full event data
|
|
211
|
-
with st.expander("View Full Event JSON"):
|
|
212
|
-
st.json(event.model_dump(mode="json"))
|
|
213
|
-
|
|
214
|
-
# Footer
|
|
215
|
-
st.markdown("---")
|
|
216
|
-
st.markdown("🍯 **HoneyMCP** - Deception Middleware for AI Agents")
|
|
217
|
-
|
|
218
|
-
# Auto-refresh button
|
|
219
|
-
if st.button("🔄 Refresh", key="refresh_btn"):
|
|
220
|
-
st.rerun()
|
|
221
|
-
|
|
222
|
-
# Auto-refresh timer info
|
|
223
|
-
st.sidebar.markdown("---")
|
|
224
|
-
st.sidebar.info("💡 Click 'Refresh' to reload events")
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if __name__ == "__main__":
|
|
228
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|