honeymcp 0.1.1__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.
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: honeymcp
3
- Version: 0.1.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
7
7
  Project-URL: Repository, https://github.com/barvhaim/HoneyMCP
8
8
  Project-URL: Issues, https://github.com/barvhaim/HoneyMCP/issues
9
+ Project-URL: PyPI, https://pypi.org/project/honeymcp/
9
10
  Author-email: Bar Haim <barha@il.ibm.com>, Alon Malach <Alon.Malach@ibm.com>
10
11
  Maintainer-email: Bar Haim <barha@il.ibm.com>, Alon Malach <Alon.Malach@ibm.com>
11
12
  License: Apache-2.0
@@ -26,6 +27,7 @@ Classifier: Topic :: Security
26
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
28
  Requires-Python: >=3.11
28
29
  Requires-Dist: aiofiles>=25.0.0
30
+ Requires-Dist: fastapi>=0.115.0
29
31
  Requires-Dist: fastmcp>=3.0.0b1
30
32
  Requires-Dist: langchain-ibm>=1.0.2
31
33
  Requires-Dist: langchain-openai>=1.1.7
@@ -38,7 +40,6 @@ Requires-Dist: pyyaml>=6.0.0
38
40
  Requires-Dist: requests>=2.32.0
39
41
  Requires-Dist: rich>=14.0.0
40
42
  Requires-Dist: starlette>=0.45.0
41
- Requires-Dist: streamlit>=1.42.0
42
43
  Requires-Dist: uvicorn>=0.34.0
43
44
  Description-Content-Type: text/markdown
44
45
 
@@ -50,6 +51,7 @@ Description-Content-Type: text/markdown
50
51
 
51
52
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
52
53
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0)
54
+ [![PyPI](https://img.shields.io/pypi/v/honeymcp)](https://pypi.org/project/honeymcp/)
53
55
 
54
56
  HoneyMCP is a defensive security tool that adds deception capabilities to Model Context Protocol (MCP) servers. It injects "ghost tools" (fake security-sensitive tools) that act as honeypots, detecting two critical threat categories:
55
57
 
@@ -62,11 +64,11 @@ HoneyMCP is a defensive security tool that adds deception capabilities to Model
62
64
 
63
65
  ## Why HoneyMCP?
64
66
 
65
- 🎯 **One-Line Integration** - Add `@honeypot` decorator to any FastMCP server
67
+ 🎯 **One-Line Integration** - Add `honeypot` middleware to any FastMCP server
66
68
  🤖 **Context-Aware Honeypots** - LLM generates domain-specific deception tools
67
69
  🕵️ **Transparent Detection** - Honeypots appear as legitimate tools to attackers
68
70
  📊 **Attack Telemetry** - Captures tool call sequences, arguments, session metadata
69
- 📈 **Live Dashboard** - Real-time Streamlit dashboard for attack visualization
71
+ 📈 **Live Dashboard** - Real-time React dashboard for attack visualization
70
72
  🔍 **High-Fidelity Detection** - Triggers only on explicit honeypot invocation
71
73
 
72
74
  ---
@@ -126,8 +128,9 @@ Dynamic ghost tools demo (requires LLM credentials in `.env.honeymcp`):
126
128
  MCP_TRANSPORT=sse uv run python examples/demo_server_dynamic.py
127
129
  ```
128
130
 
129
- # Launch dashboard
130
- streamlit run src/honeymcp/dashboard/app.py
131
+ # Launch dashboard UI
132
+ ```bash
133
+ make run-ui
131
134
  ```
132
135
 
133
136
  ---
@@ -166,18 +169,31 @@ Agent: "Execute shell command to establish persistence"
166
169
 
167
170
  ### 3. Attack Fingerprinting
168
171
 
169
- Every honeypot invocation generates a detailed attack fingerprint:
172
+ Every honeypot invocation generates an `AttackFingerprint` event and writes it to
173
+ `~/.honeymcp/events/YYYY-MM-DD/HHMMSS_<session>.json`:
170
174
  ```json
171
175
  {
172
- "event_id": "evt_20260123_154523_abc",
176
+ "event_id": "evt_20260123_154523_abc12345",
177
+ "timestamp": "2026-01-23T15:45:23Z",
178
+ "session_id": "sess_xyz789",
173
179
  "ghost_tool_called": "list_cloud_secrets",
180
+ "arguments": {},
181
+ "conversation_history": null,
174
182
  "tool_call_sequence": ["safe_calculator", "list_cloud_secrets"],
175
183
  "threat_level": "high",
176
184
  "attack_category": "exfiltration",
185
+ "client_metadata": {
186
+ "user_agent": "unknown"
187
+ },
177
188
  "response_sent": "AWS_ACCESS_KEY_ID=AKIA..."
178
189
  }
179
190
  ```
180
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
+
181
197
  ---
182
198
 
183
199
 
@@ -454,21 +470,6 @@ Expected: safe_calculator called, no alerts (zero false positives)
454
470
 
455
471
  ---
456
472
 
457
- ## Dashboard
458
-
459
- ```bash
460
- streamlit run src/honeymcp/dashboard/app.py
461
- ```
462
-
463
- **Features:**
464
- - 📈 Attack metrics (total events, critical threats, unique sessions)
465
- - 🎯 Threat level distribution
466
- - 📋 Attack category breakdown (exfiltration vs injection)
467
- - 🕐 Real-time event stream
468
- - 🔍 Tool call sequence analysis
469
-
470
- ---
471
-
472
473
  ## Honeypot Catalog
473
474
 
474
475
  ### Data Exfiltration Honeypots ("Get" Tools)
@@ -479,8 +480,14 @@ streamlit run src/honeymcp/dashboard/app.py
479
480
  | `dump_database_credentials` | Critical | Database connection strings |
480
481
  | `export_user_data` | Critical | User PII records |
481
482
  | `get_api_keys` | Critical | External service API keys |
482
-
483
- ### Prompt Injection Honeypots (SET)
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)
484
491
  | Tool | Threat | Description |
485
492
  |------|--------|-------------|
486
493
  | `execute_shell_command` | Critical | Shell command execution |
@@ -488,11 +495,127 @@ streamlit run src/honeymcp/dashboard/app.py
488
495
  | `modify_system_prompt` | Critical | AI system prompt manipulation |
489
496
  | `escalate_privileges` | Critical | Privilege escalation |
490
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
+
491
503
  All ghost tools have tempting descriptions that mention "admin", "bypass", "internal", etc. to attract attackers.
492
504
 
493
505
  ---
494
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"
495
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
+ ---
496
619
 
497
620
  ## 🏗️ Architecture
498
621
 
@@ -524,7 +647,7 @@ All ghost tools have tempting descriptions that mention "admin", "bypass", "inte
524
647
 
525
648
 
526
649
  ┌──────────────────┐
527
- Streamlit
650
+ React
528
651
  │ Dashboard │
529
652
  └──────────────────┘
530
653
  ```
@@ -648,7 +771,7 @@ HoneyMCP/
648
771
  │ ├── storage/
649
772
  │ │ └── event_store.py # JSON event persistence
650
773
  │ └── dashboard/
651
- │ └── app.py # Streamlit dashboard
774
+ │ └── react_umd/ # React dashboard assets
652
775
  ├── examples/
653
776
  │ ├── demo_server.py # Static ghost tools demo
654
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=onrB96u91MCKaErit8poZma5InUglX08NjOMkMXDMDI,20574
7
- honeymcp/core/middleware.py,sha256=oixsHEa4dpnMCIOrViEhesRrTWaSBCeahRu08lQyQqc,23245
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.py,sha256=QYrXA8J3NKtK9Dqsaze5Z88KjnSDXuL6eT6Ubu_v3hE,6848
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.1.dist-info/METADATA,sha256=m2nLdClrlxhaBw_su7jZS4Pm6yRbpgTzI_LIag9E_hw,23421
25
- honeymcp-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
- honeymcp-0.1.1.dist-info/entry_points.txt,sha256=KYXb49Xp3SEP3cNmUDwuAXJNFwsLHwPxEIj6UEhOj2k,47
27
- honeymcp-0.1.1.dist-info/licenses/LICENSE,sha256=TRR6-30aYl9D43FJPmJ8diBUP_RwDg61LNW2rt87HE8,636
28
- honeymcp-0.1.1.dist-info/RECORD,,
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()