llmsafe 0.2.1__tar.gz

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.
Files changed (47) hide show
  1. llmsafe-0.2.1/LICENSE +21 -0
  2. llmsafe-0.2.1/PKG-INFO +268 -0
  3. llmsafe-0.2.1/README.md +234 -0
  4. llmsafe-0.2.1/benchmarks/__init__.py +1 -0
  5. llmsafe-0.2.1/benchmarks/cases/insecure_mcp.json +10 -0
  6. llmsafe-0.2.1/benchmarks/cases/interprocedural_agent.py +24 -0
  7. llmsafe-0.2.1/benchmarks/cases/safe_agent.py +17 -0
  8. llmsafe-0.2.1/benchmarks/cases/safe_interprocedural.py +16 -0
  9. llmsafe-0.2.1/benchmarks/cases/vulnerable_agent.py +28 -0
  10. llmsafe-0.2.1/benchmarks/manifest.json +35 -0
  11. llmsafe-0.2.1/benchmarks/run.py +54 -0
  12. llmsafe-0.2.1/llmsafe/__init__.py +3 -0
  13. llmsafe-0.2.1/llmsafe/__main__.py +6 -0
  14. llmsafe-0.2.1/llmsafe/baseline.py +168 -0
  15. llmsafe-0.2.1/llmsafe/catalog.py +228 -0
  16. llmsafe-0.2.1/llmsafe/cli.py +216 -0
  17. llmsafe-0.2.1/llmsafe/config.py +125 -0
  18. llmsafe-0.2.1/llmsafe/models.py +97 -0
  19. llmsafe-0.2.1/llmsafe/rules/__init__.py +19 -0
  20. llmsafe-0.2.1/llmsafe/rules/agents.py +116 -0
  21. llmsafe-0.2.1/llmsafe/rules/ast_helpers.py +27 -0
  22. llmsafe-0.2.1/llmsafe/rules/base.py +30 -0
  23. llmsafe-0.2.1/llmsafe/rules/dataflow.py +581 -0
  24. llmsafe-0.2.1/llmsafe/rules/eval.py +74 -0
  25. llmsafe-0.2.1/llmsafe/rules/mcp.py +98 -0
  26. llmsafe-0.2.1/llmsafe/rules/prompts.py +83 -0
  27. llmsafe-0.2.1/llmsafe/rules/secrets.py +98 -0
  28. llmsafe-0.2.1/llmsafe/rules/shell.py +67 -0
  29. llmsafe-0.2.1/llmsafe/sarif.py +133 -0
  30. llmsafe-0.2.1/llmsafe/scanner.py +187 -0
  31. llmsafe-0.2.1/llmsafe.egg-info/PKG-INFO +268 -0
  32. llmsafe-0.2.1/llmsafe.egg-info/SOURCES.txt +45 -0
  33. llmsafe-0.2.1/llmsafe.egg-info/dependency_links.txt +1 -0
  34. llmsafe-0.2.1/llmsafe.egg-info/entry_points.txt +2 -0
  35. llmsafe-0.2.1/llmsafe.egg-info/requires.txt +10 -0
  36. llmsafe-0.2.1/llmsafe.egg-info/top_level.txt +2 -0
  37. llmsafe-0.2.1/pyproject.toml +74 -0
  38. llmsafe-0.2.1/setup.cfg +4 -0
  39. llmsafe-0.2.1/tests/test_baseline.py +88 -0
  40. llmsafe-0.2.1/tests/test_benchmark.py +18 -0
  41. llmsafe-0.2.1/tests/test_catalog.py +99 -0
  42. llmsafe-0.2.1/tests/test_cli.py +100 -0
  43. llmsafe-0.2.1/tests/test_config.py +71 -0
  44. llmsafe-0.2.1/tests/test_dataflow.py +233 -0
  45. llmsafe-0.2.1/tests/test_rules.py +96 -0
  46. llmsafe-0.2.1/tests/test_sarif.py +66 -0
  47. llmsafe-0.2.1/tests/test_scanner.py +67 -0
llmsafe-0.2.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LLMSafe contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
llmsafe-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,268 @@
1
+ Metadata-Version: 2.4
2
+ Name: llmsafe
3
+ Version: 0.2.1
4
+ Summary: Open-source security scanner for AI-powered and agentic applications.
5
+ Author: LLMSafe contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rezerpaul-crypto/llmsafe
8
+ Project-URL: Documentation, https://github.com/rezerpaul-crypto/llmsafe/tree/main/docs
9
+ Project-URL: Source, https://github.com/rezerpaul-crypto/llmsafe
10
+ Project-URL: Changelog, https://github.com/rezerpaul-crypto/llmsafe/blob/main/CHANGELOG.md
11
+ Project-URL: Issues, https://github.com/rezerpaul-crypto/llmsafe/issues
12
+ Keywords: ai,agents,llm,mcp,security,static-analysis
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Security
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
27
+ Provides-Extra: dev
28
+ Requires-Dist: build>=1.2; extra == "dev"
29
+ Requires-Dist: pytest>=7.4; extra == "dev"
30
+ Requires-Dist: pytest-cov>=4.1; extra == "dev"
31
+ Requires-Dist: ruff>=0.6; extra == "dev"
32
+ Requires-Dist: twine>=6.0; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # LLMSafe
36
+
37
+ [![CI](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/ci.yml/badge.svg)](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/ci.yml)
38
+ [![Code scanning](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/code-scanning.yml/badge.svg)](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/code-scanning.yml)
39
+ [![PyPI](https://img.shields.io/pypi/v/llmsafe.svg)](https://pypi.org/project/llmsafe/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
41
+ [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-3776AB.svg)](pyproject.toml)
42
+
43
+ LLMSafe is an open-source static security scanner for AI-powered and agentic Python
44
+ applications. It traces user input and model-controlled data into dangerous capabilities such as
45
+ code execution, shells, SQL, outbound requests, and dynamic tool dispatch.
46
+
47
+ It runs locally. Source code is not uploaded to a model or external analysis service.
48
+
49
+ > **Status:** `v0.2.1` is an early release. LLMSafe provides reviewable security signals, not a
50
+ > guarantee that an AI system is secure.
51
+
52
+ ## Why another security scanner?
53
+
54
+ Traditional Python scanners are good at finding dangerous APIs. Agentic applications add a
55
+ different question: **can untrusted user or model output reach that capability?**
56
+
57
+ ```mermaid
58
+ flowchart LR
59
+ A["User input"] --> C["Assignments and transforms"]
60
+ B["Model output"] --> C
61
+ C --> D["Shell / eval / SQL / HTTP / tool dispatch"]
62
+ D --> E["Finding with source-to-sink evidence"]
63
+ ```
64
+
65
+ LLMSafe combines focused API checks with AST-based dataflow and agent-framework rules:
66
+
67
+ ```python
68
+ def run_agent(client, user_input):
69
+ response = client.responses.create(input=user_input)
70
+ generated_code = response.output_text
71
+ return eval(generated_code)
72
+ ```
73
+
74
+ The scanner reports both the dangerous `eval()` and the path from the model response to that
75
+ sink:
76
+
77
+ ```text
78
+ agent.py:4:12: CRITICAL FLOW001 Untrusted data reaches code execution
79
+ Untrusted or model-controlled data flows into eval(). Source: model, user.
80
+ Trace 2:16: model source: client.responses.create
81
+ Trace 1:23: user source: user_input
82
+ Trace 4:12: reaches eval
83
+ Fix: Replace dynamic execution with a typed parser and an allow-listed operation.
84
+ ```
85
+
86
+ ## Detection coverage
87
+
88
+ | Family | Rule IDs | Examples |
89
+ | --- | --- | --- |
90
+ | Dataflow | `FLOW001`–`FLOW005` | Model/user data reaching code, shell, SQL, URL, or tool dispatch |
91
+ | Agent tools | `AGENT001`–`AGENT003` | Python/shell tools, dangerous capability flags, disabled approval |
92
+ | Secrets | `SECRET001`–`SECRET005` | Provider keys, tokens, private keys, hard-coded credentials |
93
+ | Python | `PY001`–`PY004` | `eval`, `exec`, unsafe pickle and YAML deserialization |
94
+ | Shell | `SHELL001`–`SHELL002` | `os.system` and `subprocess(..., shell=True)` |
95
+ | Prompt trust | `LLM001` | Dynamic data interpolated into system/developer instructions |
96
+ | MCP | `MCP001`–`MCP003` | Shell launch, remote HTTP, wildcard tool permissions |
97
+
98
+ See the [complete rule catalog](docs/rules.md) and [threat model](docs/threat-model.md).
99
+
100
+ Integrations can query the same catalog without parsing documentation:
101
+
102
+ ```bash
103
+ llmsafe --list-rules
104
+ llmsafe --list-rules --format json
105
+ ```
106
+
107
+ The versioned JSON output includes every stable ID, severity, family, description, and remediation.
108
+
109
+ ## Install
110
+
111
+ LLMSafe supports Python 3.9 and newer.
112
+
113
+ ```bash
114
+ python3 -m venv .venv
115
+ source .venv/bin/activate
116
+ python -m pip install llmsafe
117
+ ```
118
+
119
+ For development:
120
+
121
+ ```bash
122
+ git clone https://github.com/rezerpaul-crypto/llmsafe.git
123
+ cd llmsafe
124
+ python3 -m venv .venv
125
+ source .venv/bin/activate
126
+ python -m pip install -e ".[dev]"
127
+ ```
128
+
129
+ ## Use the CLI
130
+
131
+ Scan the current repository:
132
+
133
+ ```bash
134
+ llmsafe .
135
+ ```
136
+
137
+ Scan selected paths and fail on medium-or-higher findings:
138
+
139
+ ```bash
140
+ llmsafe src agent.py --fail-on medium --exclude "generated/**"
141
+ ```
142
+
143
+ Generate machine-readable reports:
144
+
145
+ ```bash
146
+ llmsafe . --format json --output reports/llmsafe.json
147
+ llmsafe . --format sarif --output reports/llmsafe.sarif
148
+ ```
149
+
150
+ Exit codes are stable for automation:
151
+
152
+ | Code | Meaning |
153
+ | --- | --- |
154
+ | `0` | No finding at or above the selected threshold |
155
+ | `1` | At least one finding reached the selected threshold |
156
+ | `2` | Invalid configuration, missing target, or scan error |
157
+
158
+ ## Repository policy
159
+
160
+ Commit a `.llmsafe.toml` file:
161
+
162
+ ```toml
163
+ [llmsafe]
164
+ exclude = ["generated/**", "vendor/**"]
165
+ fail_on = "high"
166
+ max_file_size = 1000000
167
+ disabled_rules = ["PY004"]
168
+ ```
169
+
170
+ CLI options override or extend repository policy. Policy can also live under `[tool.llmsafe]` in
171
+ `pyproject.toml`. See [configuration](docs/configuration.md).
172
+
173
+ ### Adopt LLMSafe without ignoring new risk
174
+
175
+ Existing repositories can review and commit a baseline of current findings:
176
+
177
+ ```bash
178
+ llmsafe . --write-baseline .llmsafe-baseline.json
179
+ llmsafe . --baseline .llmsafe-baseline.json
180
+ ```
181
+
182
+ The second command reports and fails only on findings not represented in the baseline. Matching is
183
+ line-independent, duplicate-aware, and deterministic so ordinary code movement does not create
184
+ noise while an additional dangerous operation is still reported. Baselines are review artifacts,
185
+ not permanent suppressions; see [incremental adoption](docs/baselines.md).
186
+
187
+ ### Suppress one reviewed finding
188
+
189
+ Place a narrow suppression on the finding line or immediately above it:
190
+
191
+ ```python
192
+ # llmsafe: ignore[PY001] -- expression is generated from a fixed internal grammar
193
+ result = eval(TRUSTED_EXPRESSION)
194
+ ```
195
+
196
+ Prefer a rule-specific suppression over a bare `llmsafe: ignore`.
197
+
198
+ ## GitHub Code Scanning
199
+
200
+ The repository includes a reusable composite action. A consumer workflow can scan, upload SARIF,
201
+ then enforce the configured threshold:
202
+
203
+ ```yaml
204
+ permissions:
205
+ contents: read
206
+ security-events: write
207
+
208
+ steps:
209
+ - uses: actions/checkout@v7
210
+ - uses: actions/setup-python@v7
211
+ with:
212
+ python-version: "3.12"
213
+ - id: llmsafe
214
+ continue-on-error: true
215
+ uses: rezerpaul-crypto/llmsafe@v0.2.1
216
+ with:
217
+ path: .
218
+ fail-on: high
219
+ - if: always()
220
+ uses: github/codeql-action/upload-sarif@v4
221
+ with:
222
+ sarif_file: ${{ steps.llmsafe.outputs.sarif-file }}
223
+ - if: steps.llmsafe.outcome == 'failure'
224
+ run: exit 1
225
+ ```
226
+
227
+ The workflow uses only `contents: read` and `security-events: write`.
228
+
229
+ ## Pre-commit
230
+
231
+ ```yaml
232
+ repos:
233
+ - repo: https://github.com/rezerpaul-crypto/llmsafe
234
+ rev: v0.2.1
235
+ hooks:
236
+ - id: llmsafe
237
+ ```
238
+
239
+ ## Benchmark
240
+
241
+ The checked-in benchmark exercises vulnerable and safe agent boundaries:
242
+
243
+ ```bash
244
+ python -m benchmarks.run
245
+ ```
246
+
247
+ Current expectations cover 18 rule-level signals across direct and local-helper code execution,
248
+ shell execution, SQL, SSRF, tool dispatch, prompt boundaries, high-impact tools, approval bypasses,
249
+ and MCP. This is a regression corpus—not an industry benchmark or a claim of real-world detection
250
+ rate. See the [benchmark methodology](docs/benchmark.md).
251
+
252
+ ## How LLMSafe fits
253
+
254
+ | Tool category | Primary strength | LLMSafe relationship |
255
+ | --- | --- | --- |
256
+ | General Python SAST | Broad language and API security checks | Complementary; LLMSafe focuses on AI/agent trust boundaries |
257
+ | Pattern-rule engines | Highly customizable organizational rules | LLMSafe supplies opinionated agent rules without rule authoring |
258
+ | Dependency scanners | Known vulnerable packages and supply chain | Out of scope; run alongside LLMSafe |
259
+ | Runtime guardrails | Enforce live policy and monitor model/tool calls | Out of scope; LLMSafe reviews source and configuration before runtime |
260
+
261
+ Read the [architecture](docs/architecture.md) for implementation boundaries and tradeoffs.
262
+
263
+ ## Contributing and security
264
+
265
+ Contributions are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) and the public
266
+ [roadmap](ROADMAP.md). Report vulnerabilities privately according to [SECURITY.md](SECURITY.md).
267
+
268
+ LLMSafe is released under the [MIT License](LICENSE).
@@ -0,0 +1,234 @@
1
+ # LLMSafe
2
+
3
+ [![CI](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/ci.yml/badge.svg)](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/ci.yml)
4
+ [![Code scanning](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/code-scanning.yml/badge.svg)](https://github.com/rezerpaul-crypto/llmsafe/actions/workflows/code-scanning.yml)
5
+ [![PyPI](https://img.shields.io/pypi/v/llmsafe.svg)](https://pypi.org/project/llmsafe/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+ [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-3776AB.svg)](pyproject.toml)
8
+
9
+ LLMSafe is an open-source static security scanner for AI-powered and agentic Python
10
+ applications. It traces user input and model-controlled data into dangerous capabilities such as
11
+ code execution, shells, SQL, outbound requests, and dynamic tool dispatch.
12
+
13
+ It runs locally. Source code is not uploaded to a model or external analysis service.
14
+
15
+ > **Status:** `v0.2.1` is an early release. LLMSafe provides reviewable security signals, not a
16
+ > guarantee that an AI system is secure.
17
+
18
+ ## Why another security scanner?
19
+
20
+ Traditional Python scanners are good at finding dangerous APIs. Agentic applications add a
21
+ different question: **can untrusted user or model output reach that capability?**
22
+
23
+ ```mermaid
24
+ flowchart LR
25
+ A["User input"] --> C["Assignments and transforms"]
26
+ B["Model output"] --> C
27
+ C --> D["Shell / eval / SQL / HTTP / tool dispatch"]
28
+ D --> E["Finding with source-to-sink evidence"]
29
+ ```
30
+
31
+ LLMSafe combines focused API checks with AST-based dataflow and agent-framework rules:
32
+
33
+ ```python
34
+ def run_agent(client, user_input):
35
+ response = client.responses.create(input=user_input)
36
+ generated_code = response.output_text
37
+ return eval(generated_code)
38
+ ```
39
+
40
+ The scanner reports both the dangerous `eval()` and the path from the model response to that
41
+ sink:
42
+
43
+ ```text
44
+ agent.py:4:12: CRITICAL FLOW001 Untrusted data reaches code execution
45
+ Untrusted or model-controlled data flows into eval(). Source: model, user.
46
+ Trace 2:16: model source: client.responses.create
47
+ Trace 1:23: user source: user_input
48
+ Trace 4:12: reaches eval
49
+ Fix: Replace dynamic execution with a typed parser and an allow-listed operation.
50
+ ```
51
+
52
+ ## Detection coverage
53
+
54
+ | Family | Rule IDs | Examples |
55
+ | --- | --- | --- |
56
+ | Dataflow | `FLOW001`–`FLOW005` | Model/user data reaching code, shell, SQL, URL, or tool dispatch |
57
+ | Agent tools | `AGENT001`–`AGENT003` | Python/shell tools, dangerous capability flags, disabled approval |
58
+ | Secrets | `SECRET001`–`SECRET005` | Provider keys, tokens, private keys, hard-coded credentials |
59
+ | Python | `PY001`–`PY004` | `eval`, `exec`, unsafe pickle and YAML deserialization |
60
+ | Shell | `SHELL001`–`SHELL002` | `os.system` and `subprocess(..., shell=True)` |
61
+ | Prompt trust | `LLM001` | Dynamic data interpolated into system/developer instructions |
62
+ | MCP | `MCP001`–`MCP003` | Shell launch, remote HTTP, wildcard tool permissions |
63
+
64
+ See the [complete rule catalog](docs/rules.md) and [threat model](docs/threat-model.md).
65
+
66
+ Integrations can query the same catalog without parsing documentation:
67
+
68
+ ```bash
69
+ llmsafe --list-rules
70
+ llmsafe --list-rules --format json
71
+ ```
72
+
73
+ The versioned JSON output includes every stable ID, severity, family, description, and remediation.
74
+
75
+ ## Install
76
+
77
+ LLMSafe supports Python 3.9 and newer.
78
+
79
+ ```bash
80
+ python3 -m venv .venv
81
+ source .venv/bin/activate
82
+ python -m pip install llmsafe
83
+ ```
84
+
85
+ For development:
86
+
87
+ ```bash
88
+ git clone https://github.com/rezerpaul-crypto/llmsafe.git
89
+ cd llmsafe
90
+ python3 -m venv .venv
91
+ source .venv/bin/activate
92
+ python -m pip install -e ".[dev]"
93
+ ```
94
+
95
+ ## Use the CLI
96
+
97
+ Scan the current repository:
98
+
99
+ ```bash
100
+ llmsafe .
101
+ ```
102
+
103
+ Scan selected paths and fail on medium-or-higher findings:
104
+
105
+ ```bash
106
+ llmsafe src agent.py --fail-on medium --exclude "generated/**"
107
+ ```
108
+
109
+ Generate machine-readable reports:
110
+
111
+ ```bash
112
+ llmsafe . --format json --output reports/llmsafe.json
113
+ llmsafe . --format sarif --output reports/llmsafe.sarif
114
+ ```
115
+
116
+ Exit codes are stable for automation:
117
+
118
+ | Code | Meaning |
119
+ | --- | --- |
120
+ | `0` | No finding at or above the selected threshold |
121
+ | `1` | At least one finding reached the selected threshold |
122
+ | `2` | Invalid configuration, missing target, or scan error |
123
+
124
+ ## Repository policy
125
+
126
+ Commit a `.llmsafe.toml` file:
127
+
128
+ ```toml
129
+ [llmsafe]
130
+ exclude = ["generated/**", "vendor/**"]
131
+ fail_on = "high"
132
+ max_file_size = 1000000
133
+ disabled_rules = ["PY004"]
134
+ ```
135
+
136
+ CLI options override or extend repository policy. Policy can also live under `[tool.llmsafe]` in
137
+ `pyproject.toml`. See [configuration](docs/configuration.md).
138
+
139
+ ### Adopt LLMSafe without ignoring new risk
140
+
141
+ Existing repositories can review and commit a baseline of current findings:
142
+
143
+ ```bash
144
+ llmsafe . --write-baseline .llmsafe-baseline.json
145
+ llmsafe . --baseline .llmsafe-baseline.json
146
+ ```
147
+
148
+ The second command reports and fails only on findings not represented in the baseline. Matching is
149
+ line-independent, duplicate-aware, and deterministic so ordinary code movement does not create
150
+ noise while an additional dangerous operation is still reported. Baselines are review artifacts,
151
+ not permanent suppressions; see [incremental adoption](docs/baselines.md).
152
+
153
+ ### Suppress one reviewed finding
154
+
155
+ Place a narrow suppression on the finding line or immediately above it:
156
+
157
+ ```python
158
+ # llmsafe: ignore[PY001] -- expression is generated from a fixed internal grammar
159
+ result = eval(TRUSTED_EXPRESSION)
160
+ ```
161
+
162
+ Prefer a rule-specific suppression over a bare `llmsafe: ignore`.
163
+
164
+ ## GitHub Code Scanning
165
+
166
+ The repository includes a reusable composite action. A consumer workflow can scan, upload SARIF,
167
+ then enforce the configured threshold:
168
+
169
+ ```yaml
170
+ permissions:
171
+ contents: read
172
+ security-events: write
173
+
174
+ steps:
175
+ - uses: actions/checkout@v7
176
+ - uses: actions/setup-python@v7
177
+ with:
178
+ python-version: "3.12"
179
+ - id: llmsafe
180
+ continue-on-error: true
181
+ uses: rezerpaul-crypto/llmsafe@v0.2.1
182
+ with:
183
+ path: .
184
+ fail-on: high
185
+ - if: always()
186
+ uses: github/codeql-action/upload-sarif@v4
187
+ with:
188
+ sarif_file: ${{ steps.llmsafe.outputs.sarif-file }}
189
+ - if: steps.llmsafe.outcome == 'failure'
190
+ run: exit 1
191
+ ```
192
+
193
+ The workflow uses only `contents: read` and `security-events: write`.
194
+
195
+ ## Pre-commit
196
+
197
+ ```yaml
198
+ repos:
199
+ - repo: https://github.com/rezerpaul-crypto/llmsafe
200
+ rev: v0.2.1
201
+ hooks:
202
+ - id: llmsafe
203
+ ```
204
+
205
+ ## Benchmark
206
+
207
+ The checked-in benchmark exercises vulnerable and safe agent boundaries:
208
+
209
+ ```bash
210
+ python -m benchmarks.run
211
+ ```
212
+
213
+ Current expectations cover 18 rule-level signals across direct and local-helper code execution,
214
+ shell execution, SQL, SSRF, tool dispatch, prompt boundaries, high-impact tools, approval bypasses,
215
+ and MCP. This is a regression corpus—not an industry benchmark or a claim of real-world detection
216
+ rate. See the [benchmark methodology](docs/benchmark.md).
217
+
218
+ ## How LLMSafe fits
219
+
220
+ | Tool category | Primary strength | LLMSafe relationship |
221
+ | --- | --- | --- |
222
+ | General Python SAST | Broad language and API security checks | Complementary; LLMSafe focuses on AI/agent trust boundaries |
223
+ | Pattern-rule engines | Highly customizable organizational rules | LLMSafe supplies opinionated agent rules without rule authoring |
224
+ | Dependency scanners | Known vulnerable packages and supply chain | Out of scope; run alongside LLMSafe |
225
+ | Runtime guardrails | Enforce live policy and monitor model/tool calls | Out of scope; LLMSafe reviews source and configuration before runtime |
226
+
227
+ Read the [architecture](docs/architecture.md) for implementation boundaries and tradeoffs.
228
+
229
+ ## Contributing and security
230
+
231
+ Contributions are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md) and the public
232
+ [roadmap](ROADMAP.md). Report vulnerabilities privately according to [SECURITY.md](SECURITY.md).
233
+
234
+ LLMSafe is released under the [MIT License](LICENSE).
@@ -0,0 +1 @@
1
+ """Reproducible LLMSafe security benchmark."""
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "remote-admin": {
4
+ "command": "sh",
5
+ "args": ["-c", "download-and-run"],
6
+ "url": "http://tools.example.org/mcp",
7
+ "allowedTools": ["*"]
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,24 @@
1
+ """Vulnerable local-helper flows used by the LLMSafe regression benchmark."""
2
+
3
+ import subprocess
4
+
5
+ import requests
6
+
7
+
8
+ def evaluate(value):
9
+ return eval(value)
10
+
11
+
12
+ def execute(value):
13
+ return subprocess.run(value, shell=True)
14
+
15
+
16
+ def fetch(value):
17
+ return requests.get(value)
18
+
19
+
20
+ def run_agent(user_input, model_output):
21
+ result = evaluate(model_output)
22
+ execute(user_input)
23
+ fetch(model_output)
24
+ return result
@@ -0,0 +1,17 @@
1
+ """Equivalent agent boundaries designed to remain free of LLMSafe findings."""
2
+
3
+ import subprocess
4
+
5
+ ALLOWED_TOPICS = {"security", "python"}
6
+
7
+
8
+ def search(topic: str, cursor):
9
+ if topic not in ALLOWED_TOPICS:
10
+ raise ValueError("Unsupported topic")
11
+ cursor.execute("SELECT * FROM memory WHERE topic = ?", [topic])
12
+ return subprocess.run(["agent-tool", "--topic", topic], check=True)
13
+
14
+
15
+ def dispatch_search():
16
+ tools = {"search": search}
17
+ return tools["search"]
@@ -0,0 +1,16 @@
1
+ """Safe local-helper calls used by the LLMSafe regression benchmark."""
2
+
3
+ import requests
4
+
5
+
6
+ def fetch(value):
7
+ return requests.get(value)
8
+
9
+
10
+ def lookup(cursor, statement):
11
+ return cursor.execute(statement)
12
+
13
+
14
+ def run(cursor):
15
+ fetch("https://api.example.org/health")
16
+ return lookup(cursor, "SELECT id FROM documents WHERE active = true")
@@ -0,0 +1,28 @@
1
+ """Intentionally vulnerable agent used by the LLMSafe benchmark."""
2
+
3
+ import subprocess
4
+
5
+ import requests
6
+ from langchain_experimental.tools import PythonREPLTool
7
+
8
+
9
+ class AgentRunner:
10
+ """Minimal benchmark stand-in for an agent framework runner."""
11
+
12
+ def __init__(self, **options):
13
+ self.options = options
14
+
15
+
16
+ def run_agent(client, user_input, cursor, tools):
17
+ system_prompt = f"You are an administrator. Follow this request: {user_input}"
18
+ response = client.responses.create(input=user_input, instructions=system_prompt)
19
+ model_output = response.output_text
20
+
21
+ eval(model_output)
22
+ subprocess.run(f"agent-tool {user_input}", shell=True)
23
+ cursor.execute(f"SELECT * FROM memory WHERE topic = '{user_input}'")
24
+ requests.get(user_input)
25
+ tools[model_output]()
26
+
27
+ dangerous_tool = PythonREPLTool()
28
+ AgentRunner(tools=[dangerous_tool], require_approval=False)
@@ -0,0 +1,35 @@
1
+ {
2
+ "cases": [
3
+ {
4
+ "path": "cases/vulnerable_agent.py",
5
+ "expected_rules": [
6
+ "AGENT001",
7
+ "AGENT003",
8
+ "FLOW001",
9
+ "FLOW002",
10
+ "FLOW003",
11
+ "FLOW004",
12
+ "FLOW005",
13
+ "LLM001",
14
+ "PY001",
15
+ "SHELL002"
16
+ ]
17
+ },
18
+ {
19
+ "path": "cases/safe_agent.py",
20
+ "expected_rules": []
21
+ },
22
+ {
23
+ "path": "cases/interprocedural_agent.py",
24
+ "expected_rules": ["FLOW001", "FLOW002", "FLOW004", "PY001", "SHELL002"]
25
+ },
26
+ {
27
+ "path": "cases/safe_interprocedural.py",
28
+ "expected_rules": []
29
+ },
30
+ {
31
+ "path": "cases/insecure_mcp.json",
32
+ "expected_rules": ["MCP001", "MCP002", "MCP003"]
33
+ }
34
+ ]
35
+ }