offsec-ai 2.0.0__tar.gz → 2.0.2__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.
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/CHANGELOG.md +18 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/CONTRIBUTING.md +4 -4
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/LICENSE +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/PKG-INFO +30 -6
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/README.md +24 -3
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/SECURITY.md +5 -5
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/DOCKER.md +110 -9
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/assets/logo.svg +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/quickstart.md +6 -6
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/pyproject.toml +6 -3
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/__init__.py +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/ai_owasp_scanner.py +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/hybrid_identity_checker.py +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/l7_detector.py +1 -1
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/mcp_attacker.py +4 -4
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/mcp_scanner.py +2 -2
- offsec_ai-2.0.2/tests/test_mtls.py +102 -0
- offsec_ai-2.0.2/tests/test_mtls_integration.py +82 -0
- offsec_ai-2.0.0/tests/test_dns_trace.py +0 -85
- offsec_ai-2.0.0/tests/test_mtls.py +0 -159
- offsec_ai-2.0.0/tests/test_mtls_integration.py +0 -193
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/.gitignore +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/api.md +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/azure-ad-flow-explained.md +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/hybrid-identity.md +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/docs/owasp-scanner.md +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/examples/comprehensive_examples.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/examples/mtls_examples.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/examples/owasp_scan_examples.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/examples/usage_examples.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/__main__.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/cli.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/__init__.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/cert_analyzer.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/llm_judge.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/mtls_checker.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/owasp_scanner.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/port_scanner.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/core/security_headers.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/__init__.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/ai_owasp_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/l7_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/mcp_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/mtls_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/owasp_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/models/scan_result.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/py.typed +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/__init__.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/ai_owasp_payloads.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/ai_owasp_remediation.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/common_ports.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/exporters.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/l7_signatures.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/mcp_cve_db.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/mcp_payloads.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/src/offsec_ai/utils/owasp_remediation.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/tests/conftest.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/tests/test_ai_owasp.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/tests/test_mcp_attacker.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/tests/test_mcp_scanner.py +0 -0
- {offsec_ai-2.0.0 → offsec_ai-2.0.2}/tests/test_port_scanner.py +0 -0
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.2] - 2026-06-29
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- README logo replaced with inline ASCII art (no external image dependency)
|
|
12
|
+
- User-Agent strings updated from `SimplePortChecker/1.0` to `offsec-ai/2.0` in `L7Detector` and `HybridIdentityChecker`
|
|
13
|
+
- `reportlab>=4.0.0` promoted to core dependency in `pyproject.toml` (was missing, caused `ModuleNotFoundError` on fresh installs)
|
|
14
|
+
- Docker image now installs `[ai]` extras (`openai`, `anthropic`) so LLM judge works at runtime via env vars
|
|
15
|
+
- Dockerfile redundant pre-installs removed; `pip install ".[ai]"` is now the single install step
|
|
16
|
+
- `docker-push` and `docker-release` Makefile targets added with auto-versioning from `pyproject.toml`
|
|
17
|
+
- CI/CD: `docker.yml` image labels updated (title, description); unused `build-args` removed
|
|
18
|
+
- CI/CD: `publish.yml` PyPI environment URL no longer pins a hardcoded version
|
|
19
|
+
- Stale files removed: `PROJECT_STRUCTURE.md`, `HYBRID_IDENTITY_QUICKREF.md`, `IMPLEMENTATION_HYBRID_IDENTITY.md`, `MANIFEST.in`, empty `scripts/` dir
|
|
20
|
+
- `tests/test_dns_trace.py` removed (was a live-network script, not a pytest test)
|
|
21
|
+
- `tests/test_mtls.py` and `tests/test_mtls_integration.py` rewritten as proper `assert`-based pytest tests
|
|
22
|
+
- `setup_dev.sh` updated: branding, venv path (`.venv`), and `[ai]` extras
|
|
23
|
+
|
|
8
24
|
## [2.0.0] - 2026-06-29
|
|
9
25
|
|
|
10
26
|
### Added — AI / LLM Security (fresh start as `offsec-ai`)
|
|
@@ -560,5 +576,6 @@ All existing functionality (port scanning, L7 detection, mTLS, certificate analy
|
|
|
560
576
|
- cryptography: For certificate handling
|
|
561
577
|
- certifi: For CA bundle management
|
|
562
578
|
|
|
563
|
-
[Unreleased]: https://github.com/
|
|
579
|
+
[Unreleased]: https://github.com/Htunn/offsec-ai/compare/v2.0.1...HEAD
|
|
580
|
+
[2.0.1]: https://github.com/Htunn/offsec-ai/compare/v2.0.0...v2.0.1
|
|
564
581
|
[2.0.0]: https://github.com/htunn/offsec-ai/releases/tag/v2.0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Contributing to
|
|
1
|
+
# Contributing to offsec-ai
|
|
2
2
|
|
|
3
|
-
Thank you for your interest in contributing to
|
|
3
|
+
Thank you for your interest in contributing to offsec-ai! This guide will help you get started.
|
|
4
4
|
|
|
5
5
|
## Code of Conduct
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ This project adheres to a code of conduct. By participating, you are expected to
|
|
|
12
12
|
|
|
13
13
|
1. **Fork and clone the repository**
|
|
14
14
|
```bash
|
|
15
|
-
git clone https://github.com/
|
|
15
|
+
git clone https://github.com/Htunn/offsec-ai.git
|
|
16
16
|
cd offsec-ai
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -327,4 +327,4 @@ Contributors will be recognized in:
|
|
|
327
327
|
- **Release notes** for significant contributions
|
|
328
328
|
- **GitHub contributors** page
|
|
329
329
|
|
|
330
|
-
Thank you for contributing to
|
|
330
|
+
Thank you for contributing to offsec-ai! 🎉
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: offsec-ai
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Offensive-security toolkit: port scanning, L7/WAF detection, mTLS, certificate analysis, OWASP Top 10, AI/LLM OWASP Top 10 black-box probing, and MCP endpoint security scanning
|
|
5
5
|
Project-URL: Homepage, https://github.com/htunn/offsec-ai
|
|
6
6
|
Project-URL: Repository, https://github.com/htunn/offsec-ai
|
|
7
7
|
Project-URL: Issues, https://github.com/htunn/offsec-ai/issues
|
|
8
8
|
Project-URL: Documentation, https://github.com/htunn/offsec-ai#readme
|
|
9
|
-
Author
|
|
10
|
-
|
|
9
|
+
Author: Htunn
|
|
10
|
+
Author-email: htunnthuthu.linux@gmail.com
|
|
11
|
+
Maintainer: Htunn
|
|
12
|
+
Maintainer-email: htunnthuthu.linux@gmail.com
|
|
11
13
|
License: MIT
|
|
12
14
|
License-File: LICENSE
|
|
13
15
|
Keywords: ai,ai-security,certificate,certificate-analysis,firewall,l7-protection,llm,mcp,model-context-protocol,network,offensive-security,owasp,pentest,pki,port-scanner,red-team,security,ssl,tls,waf
|
|
@@ -37,6 +39,7 @@ Requires-Dist: httpx>=0.25.0
|
|
|
37
39
|
Requires-Dist: mcp>=1.0.0
|
|
38
40
|
Requires-Dist: pydantic>=2.0.0
|
|
39
41
|
Requires-Dist: python-nmap>=0.7.1
|
|
42
|
+
Requires-Dist: reportlab>=4.0.0
|
|
40
43
|
Requires-Dist: requests>=2.31.0
|
|
41
44
|
Requires-Dist: rich>=13.0.0
|
|
42
45
|
Provides-Extra: ai
|
|
@@ -56,9 +59,15 @@ Provides-Extra: gemini
|
|
|
56
59
|
Requires-Dist: google-generativeai>=0.7.0; extra == 'gemini'
|
|
57
60
|
Description-Content-Type: text/markdown
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
```
|
|
63
|
+
██████╗ ███████╗███████╗███████╗███████╗ ██████╗ █████╗ ██╗
|
|
64
|
+
██╔═══██╗██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝ ██╔══██╗██║
|
|
65
|
+
██║ ██║█████╗ █████╗ ███████╗█████╗ ██║ █████╗███████║██║
|
|
66
|
+
██║ ██║██╔══╝ ██╔══╝ ╚════██║██╔══╝ ██║ ╚════╝██╔══██║██║
|
|
67
|
+
╚██████╔╝██║ ██║ ███████║███████╗╚██████╗ ██║ ██║██║
|
|
68
|
+
╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
|
|
69
|
+
Offensive-Security Toolkit · AI/LLM · MCP · Red-Team
|
|
70
|
+
```
|
|
62
71
|
|
|
63
72
|
<p align="center">
|
|
64
73
|
<a href="https://pypi.org/project/offsec-ai/"><img src="https://img.shields.io/pypi/v/offsec-ai" alt="PyPI Version"/></a>
|
|
@@ -554,8 +563,23 @@ docker run --rm htunnthuthu/offsec-ai:latest owasp-scan example.com
|
|
|
554
563
|
docker run --rm -v $(pwd):/app/output htunnthuthu/offsec-ai:latest \
|
|
555
564
|
ai-owasp-scan https://api.example.com/v1/chat/completions \
|
|
556
565
|
--output /app/output/llm-report.json
|
|
566
|
+
|
|
567
|
+
# LLM Judge — openai, anthropic, or gemini key auto-detected; no extra install needed
|
|
568
|
+
docker run --rm \
|
|
569
|
+
-e OPENAI_API_KEY=sk-... \
|
|
570
|
+
htunnthuthu/offsec-ai:latest \
|
|
571
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
572
|
+
|
|
573
|
+
# Custom OpenAI-compatible backend (Ollama, LM Studio, Azure OpenAI…)
|
|
574
|
+
docker run --rm \
|
|
575
|
+
-e OFFSEC_LLM_BASE_URL=http://host.docker.internal:11434/v1 \
|
|
576
|
+
-e OFFSEC_LLM_MODEL=llama3 \
|
|
577
|
+
htunnthuthu/offsec-ai:latest \
|
|
578
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
557
579
|
```
|
|
558
580
|
|
|
581
|
+
See [docs/DOCKER.md](docs/DOCKER.md) for the full Docker reference including CI/CD integration, Kubernetes jobs, Makefile publish targets, and troubleshooting.
|
|
582
|
+
|
|
559
583
|
---
|
|
560
584
|
|
|
561
585
|
## Configuration
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
```
|
|
2
|
+
██████╗ ███████╗███████╗███████╗███████╗ ██████╗ █████╗ ██╗
|
|
3
|
+
██╔═══██╗██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝ ██╔══██╗██║
|
|
4
|
+
██║ ██║█████╗ █████╗ ███████╗█████╗ ██║ █████╗███████║██║
|
|
5
|
+
██║ ██║██╔══╝ ██╔══╝ ╚════██║██╔══╝ ██║ ╚════╝██╔══██║██║
|
|
6
|
+
╚██████╔╝██║ ██║ ███████║███████╗╚██████╗ ██║ ██║██║
|
|
7
|
+
╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝
|
|
8
|
+
Offensive-Security Toolkit · AI/LLM · MCP · Red-Team
|
|
9
|
+
```
|
|
4
10
|
|
|
5
11
|
<p align="center">
|
|
6
12
|
<a href="https://pypi.org/project/offsec-ai/"><img src="https://img.shields.io/pypi/v/offsec-ai" alt="PyPI Version"/></a>
|
|
@@ -496,8 +502,23 @@ docker run --rm htunnthuthu/offsec-ai:latest owasp-scan example.com
|
|
|
496
502
|
docker run --rm -v $(pwd):/app/output htunnthuthu/offsec-ai:latest \
|
|
497
503
|
ai-owasp-scan https://api.example.com/v1/chat/completions \
|
|
498
504
|
--output /app/output/llm-report.json
|
|
505
|
+
|
|
506
|
+
# LLM Judge — openai, anthropic, or gemini key auto-detected; no extra install needed
|
|
507
|
+
docker run --rm \
|
|
508
|
+
-e OPENAI_API_KEY=sk-... \
|
|
509
|
+
htunnthuthu/offsec-ai:latest \
|
|
510
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
511
|
+
|
|
512
|
+
# Custom OpenAI-compatible backend (Ollama, LM Studio, Azure OpenAI…)
|
|
513
|
+
docker run --rm \
|
|
514
|
+
-e OFFSEC_LLM_BASE_URL=http://host.docker.internal:11434/v1 \
|
|
515
|
+
-e OFFSEC_LLM_MODEL=llama3 \
|
|
516
|
+
htunnthuthu/offsec-ai:latest \
|
|
517
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
499
518
|
```
|
|
500
519
|
|
|
520
|
+
See [docs/DOCKER.md](docs/DOCKER.md) for the full Docker reference including CI/CD integration, Kubernetes jobs, Makefile publish targets, and troubleshooting.
|
|
521
|
+
|
|
501
522
|
---
|
|
502
523
|
|
|
503
524
|
## Configuration
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Supported Versions
|
|
4
4
|
|
|
5
|
-
We provide security updates for the following versions of
|
|
5
|
+
We provide security updates for the following versions of offsec-ai:
|
|
6
6
|
|
|
7
7
|
| Version | Supported |
|
|
8
8
|
| ------- | ------------------ |
|
|
9
|
-
|
|
|
10
|
-
|
|
|
9
|
+
| 2.x | :white_check_mark: |
|
|
10
|
+
| 1.x | :x: |
|
|
11
11
|
|
|
12
12
|
## Reporting a Vulnerability
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@ We take security vulnerabilities seriously. If you discover a security vulnerabi
|
|
|
15
15
|
|
|
16
16
|
### How to Report
|
|
17
17
|
|
|
18
|
-
1. **Email**: Send an email to `htunnthuthu.linux@gmail.com` with the subject line "Security Vulnerability in
|
|
18
|
+
1. **Email**: Send an email to `htunnthuthu.linux@gmail.com` with the subject line "Security Vulnerability in offsec-ai"
|
|
19
19
|
2. **Include**:
|
|
20
20
|
- A description of the vulnerability
|
|
21
21
|
- Steps to reproduce the issue
|
|
@@ -38,7 +38,7 @@ We practice responsible disclosure:
|
|
|
38
38
|
|
|
39
39
|
## Security Best Practices
|
|
40
40
|
|
|
41
|
-
When using
|
|
41
|
+
When using offsec-ai:
|
|
42
42
|
|
|
43
43
|
1. **Network Scanning**: Only scan networks you own or have explicit permission to test
|
|
44
44
|
2. **Rate Limiting**: Use appropriate timeout and concurrency settings to avoid overwhelming target systems
|
|
@@ -9,6 +9,7 @@ A comprehensive, lightweight Docker container for network secu## 🔒 Certificat
|
|
|
9
9
|
| Tag | Description | Size | Architectures |
|
|
10
10
|
|-----|-------------|------|---------------|
|
|
11
11
|
| `latest` | Latest stable release | ~60MB | `linux/amd64`, `linux/arm64` |
|
|
12
|
+
| `v2.0.1` | v2.0.1 — logo fix, docs cleanup | ~60MB | `linux/amd64`, `linux/arm64` |
|
|
12
13
|
| `v2.0.0` | v2.0.0 — AI/LLM scanner, MCP scanner, Gemini judge | ~60MB | `linux/amd64`, `linux/arm64` |
|
|
13
14
|
|
|
14
15
|
**Recommendation**: Use `latest` for the most recent features, or pin to specific version tags for production deployments.
|
|
@@ -259,9 +260,73 @@ spec:
|
|
|
259
260
|
- ✅ OCSP and CRL URL extraction for revocation checking
|
|
260
261
|
- ✅ Certificate fingerprint generation (SHA-1, SHA-256)
|
|
261
262
|
|
|
262
|
-
##
|
|
263
|
+
## 🤖 AI / LLM Security Usage
|
|
264
|
+
|
|
265
|
+
The image ships with `openai` and `anthropic` pre-installed (`[ai]` extra). Pass an API key at runtime to enable the **LLM Judge** for smarter semantic vulnerability detection.
|
|
266
|
+
|
|
267
|
+
### AI OWASP Top 10 Scan (rule-based, no key required)
|
|
268
|
+
```bash
|
|
269
|
+
docker run --rm htunnthuthu/offsec-ai:latest \
|
|
270
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### AI OWASP Top 10 Scan with LLM Judge
|
|
263
274
|
|
|
264
|
-
|
|
275
|
+
```bash
|
|
276
|
+
# OpenAI judge
|
|
277
|
+
docker run --rm \
|
|
278
|
+
-e OPENAI_API_KEY=sk-... \
|
|
279
|
+
htunnthuthu/offsec-ai:latest \
|
|
280
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
281
|
+
|
|
282
|
+
# Anthropic judge
|
|
283
|
+
docker run --rm \
|
|
284
|
+
-e ANTHROPIC_API_KEY=sk-ant-... \
|
|
285
|
+
htunnthuthu/offsec-ai:latest \
|
|
286
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
287
|
+
|
|
288
|
+
# Google Gemini judge (no extra package needed)
|
|
289
|
+
docker run --rm \
|
|
290
|
+
-e GEMINI_API_KEY=AIzaSy... \
|
|
291
|
+
htunnthuthu/offsec-ai:latest \
|
|
292
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
293
|
+
|
|
294
|
+
# Custom OpenAI-compatible endpoint (Ollama, LM Studio, Azure OpenAI, etc.)
|
|
295
|
+
docker run --rm \
|
|
296
|
+
-e OFFSEC_LLM_BASE_URL=http://host.docker.internal:11434/v1 \
|
|
297
|
+
-e OFFSEC_LLM_MODEL=llama3 \
|
|
298
|
+
htunnthuthu/offsec-ai:latest \
|
|
299
|
+
ai-owasp-scan https://api.example.com/v1/chat/completions --llm-judge
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### MCP Security Scan
|
|
303
|
+
```bash
|
|
304
|
+
# Scan an MCP endpoint
|
|
305
|
+
docker run --rm htunnthuthu/offsec-ai:latest \
|
|
306
|
+
mcp-scan https://mcp.example.com/mcp
|
|
307
|
+
|
|
308
|
+
# Active MCP attack (requires authorization flag)
|
|
309
|
+
docker run --rm htunnthuthu/offsec-ai:latest \
|
|
310
|
+
mcp-attack https://mcp.example.com/mcp --i-have-authorization --mode deep
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 🔧 Configuration & Environment
|
|
316
|
+
|
|
317
|
+
### LLM / AI Judge Environment Variables
|
|
318
|
+
|
|
319
|
+
| Variable | Provider | Description |
|
|
320
|
+
|----------|----------|-------------|
|
|
321
|
+
| `OPENAI_API_KEY` | OpenAI | Enables OpenAI judge (e.g. `gpt-4o-mini`) |
|
|
322
|
+
| `ANTHROPIC_API_KEY` | Anthropic | Enables Anthropic judge (e.g. `claude-3-haiku`) |
|
|
323
|
+
| `GEMINI_API_KEY` | Google | Enables Gemini judge (e.g. `gemini-1.5-flash`) |
|
|
324
|
+
| `OFFSEC_LLM_BASE_URL` | Any OpenAI-compatible | Use a custom/local endpoint as the judge backend |
|
|
325
|
+
| `OFFSEC_LLM_MODEL` | All | Override the default model name |
|
|
326
|
+
|
|
327
|
+
Provider is **auto-detected** from whichever key is set; `OFFSEC_LLM_BASE_URL` takes precedence over `OPENAI_API_KEY`.
|
|
328
|
+
|
|
329
|
+
### General Environment Variables
|
|
265
330
|
```bash
|
|
266
331
|
# Set timeout for operations
|
|
267
332
|
docker run --rm -e TIMEOUT=30 htunnthuthu/offsec-ai:latest scan example.com
|
|
@@ -293,12 +358,12 @@ docker run --rm -v /host/certs:/app/certs \
|
|
|
293
358
|
## 🔒 Security Features
|
|
294
359
|
|
|
295
360
|
### Non-Root User
|
|
296
|
-
- ✅ Container runs as non-root user `
|
|
361
|
+
- ✅ Container runs as non-root user `appuser` (UID: 1000)
|
|
297
362
|
- ✅ No privileged access required
|
|
298
363
|
- ✅ Minimal attack surface
|
|
299
364
|
|
|
300
365
|
### Minimal Dependencies
|
|
301
|
-
- ✅ Based on
|
|
366
|
+
- ✅ Based on Debian slim for minimal footprint
|
|
302
367
|
- ✅ Only essential packages included
|
|
303
368
|
- ✅ Regular security updates via automated builds
|
|
304
369
|
|
|
@@ -310,17 +375,18 @@ docker run --rm -v /host/certs:/app/certs \
|
|
|
310
375
|
## 🏷️ Image Specifications
|
|
311
376
|
|
|
312
377
|
### Base Image
|
|
313
|
-
- **OS**:
|
|
378
|
+
- **OS**: Debian GNU/Linux 12 Bookworm slim (`python:3.12-slim-bookworm`)
|
|
314
379
|
- **Python**: 3.12+
|
|
315
380
|
- **Architecture**: Multi-arch (AMD64, ARM64)
|
|
316
|
-
- **User**: Non-root (`
|
|
381
|
+
- **User**: Non-root (`appuser:appuser`, UID/GID 1000)
|
|
317
382
|
|
|
318
383
|
### Installed Tools
|
|
319
|
-
- ✅
|
|
384
|
+
- ✅ `offsec-ai` (latest version)
|
|
320
385
|
- ✅ Python runtime and required dependencies
|
|
386
|
+
- ✅ `openai` & `anthropic` packages — bundled via `[ai]` extra; LLM judge activates automatically when you pass an API key env var
|
|
321
387
|
- ✅ SSL/TLS libraries for certificate handling
|
|
322
388
|
- ✅ DNS resolution utilities
|
|
323
|
-
- ✅
|
|
389
|
+
- ✅ `nmap` for port scanning
|
|
324
390
|
- ✅ Cryptography libraries for certificate analysis
|
|
325
391
|
|
|
326
392
|
### Performance
|
|
@@ -429,7 +495,42 @@ docker run --rm --memory=512m htunnthuthu/offsec-ai:latest scan example.com
|
|
|
429
495
|
docker run --rm --cpus=2 htunnthuthu/offsec-ai:latest full-scan example.com
|
|
430
496
|
```
|
|
431
497
|
|
|
432
|
-
##
|
|
498
|
+
## �️ Building & Publishing Locally
|
|
499
|
+
|
|
500
|
+
The `Makefile` provides convenience targets for building and pushing to Docker Hub.
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
# Build the image locally
|
|
504
|
+
make docker-build
|
|
505
|
+
|
|
506
|
+
# Build without cache
|
|
507
|
+
make docker-build-no-cache
|
|
508
|
+
|
|
509
|
+
# Build multi-arch (linux/amd64 + linux/arm64) — requires docker buildx
|
|
510
|
+
make docker-build-multi
|
|
511
|
+
|
|
512
|
+
# Push to Docker Hub (builds first, then tags + pushes :version and :latest)
|
|
513
|
+
make docker-push # uses DOCKER_USERNAME=htunn by default
|
|
514
|
+
make docker-push DOCKER_USERNAME=youruser # override username
|
|
515
|
+
|
|
516
|
+
# Full release in one command
|
|
517
|
+
make docker-release # equivalent to docker-build + docker-push
|
|
518
|
+
|
|
519
|
+
# Test the local image
|
|
520
|
+
make docker-test
|
|
521
|
+
|
|
522
|
+
# Scan image for vulnerabilities (requires trivy)
|
|
523
|
+
make docker-scan
|
|
524
|
+
|
|
525
|
+
# Clean up local Docker artifacts
|
|
526
|
+
make docker-clean
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The `DOCKER_VERSION` is read automatically from `pyproject.toml`, so the published tags match the package version exactly.
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## �🔗 Related Links
|
|
433
534
|
|
|
434
535
|
- **GitHub Repository**: [Htunn/offsec-ai](https://github.com/Htunn/offsec-ai)
|
|
435
536
|
- **PyPI Package**: [offsec-ai](https://pypi.org/project/offsec-ai/)
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<!-- Version badge -->
|
|
50
50
|
<rect x="62" y="94" width="52" height="16" rx="3" fill="#cc000033" stroke="#cc000066" stroke-width="0.8"/>
|
|
51
51
|
<text x="88" y="106" font-family="'Courier New', Courier, monospace" font-size="9"
|
|
52
|
-
fill="#ff6666" text-anchor="middle">v2.0.
|
|
52
|
+
fill="#ff6666" text-anchor="middle">v2.0.1</text>
|
|
53
53
|
|
|
54
54
|
<!-- Right decorative dots (terminal-like) -->
|
|
55
55
|
<circle cx="470" cy="26" r="5" fill="#ff4444" opacity="0.9"/>
|
|
@@ -28,9 +28,8 @@ offsec-ai ai-owasp-scan https://api.example.com/v1/chat/completions \
|
|
|
28
28
|
offsec-ai mcp-scan https://mcp.example.com/mcp
|
|
29
29
|
offsec-ai mcp-scan https://mcp.example.com/mcp --output report.json
|
|
30
30
|
|
|
31
|
-
# MCP attacker (requires --
|
|
32
|
-
offsec-ai mcp-attack https://mcp.example.com/mcp --
|
|
33
|
-
--auth-token "$TOKEN"
|
|
31
|
+
# MCP attacker (requires --i-have-authorization flag)
|
|
32
|
+
offsec-ai mcp-attack https://mcp.example.com/mcp --i-have-authorization
|
|
34
33
|
```
|
|
35
34
|
|
|
36
35
|
### Python API
|
|
@@ -167,6 +166,7 @@ offsec-ai scan example.com --verbose
|
|
|
167
166
|
## Examples
|
|
168
167
|
|
|
169
168
|
See the `examples/` directory for complete usage examples:
|
|
170
|
-
- `usage_examples.py`
|
|
171
|
-
- `
|
|
172
|
-
- `
|
|
169
|
+
- `usage_examples.py` — Core infrastructure scanning examples
|
|
170
|
+
- `comprehensive_examples.py` — All features with detailed output
|
|
171
|
+
- `mtls_examples.py` — mTLS testing and certificate generation
|
|
172
|
+
- `owasp_scan_examples.py` — OWASP Top 10 scanning with PDF/CSV export
|
|
@@ -4,16 +4,18 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "offsec-ai"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.2"
|
|
8
8
|
description = "Offensive-security toolkit: port scanning, L7/WAF detection, mTLS, certificate analysis, OWASP Top 10, AI/LLM OWASP Top 10 black-box probing, and MCP endpoint security scanning"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = {text = "MIT"}
|
|
12
12
|
authors = [
|
|
13
|
-
{name = "
|
|
13
|
+
{name = "Htunn"},
|
|
14
|
+
{email = "htunnthuthu.linux@gmail.com"}
|
|
14
15
|
]
|
|
15
16
|
maintainers = [
|
|
16
|
-
{name = "
|
|
17
|
+
{name = "Htunn"},
|
|
18
|
+
{email = "htunnthuthu.linux@gmail.com"}
|
|
17
19
|
]
|
|
18
20
|
keywords = ["firewall", "port-scanner", "l7-protection", "waf", "network", "security", "ssl", "tls", "certificate", "certificate-analysis", "pki", "offensive-security", "red-team", "pentest", "ai", "llm", "mcp", "owasp", "ai-security", "model-context-protocol"]
|
|
19
21
|
classifiers = [
|
|
@@ -46,6 +48,7 @@ dependencies = [
|
|
|
46
48
|
"cryptography>=41.0.0",
|
|
47
49
|
"mcp>=1.0.0",
|
|
48
50
|
"httpx>=0.25.0",
|
|
51
|
+
"reportlab>=4.0.0",
|
|
49
52
|
]
|
|
50
53
|
|
|
51
54
|
[project.optional-dependencies]
|
|
@@ -91,7 +91,7 @@ class HybridIdentityChecker:
|
|
|
91
91
|
timeout: Request timeout in seconds
|
|
92
92
|
"""
|
|
93
93
|
self.timeout = timeout
|
|
94
|
-
self.user_agent = "
|
|
94
|
+
self.user_agent = "offsec-ai/2.0 (Hybrid Identity Scanner)"
|
|
95
95
|
|
|
96
96
|
async def check(self, fqdn: str) -> HybridIdentityResult:
|
|
97
97
|
"""
|
|
@@ -55,7 +55,7 @@ class L7Detector:
|
|
|
55
55
|
user_agent: Custom User-Agent string
|
|
56
56
|
"""
|
|
57
57
|
self.timeout = timeout
|
|
58
|
-
self.user_agent = user_agent or "
|
|
58
|
+
self.user_agent = user_agent or "offsec-ai/2.0 (Security Scanner)"
|
|
59
59
|
self.signatures = L7_SIGNATURES
|
|
60
60
|
|
|
61
61
|
async def detect(self, host: str, port: int = None, path: str = "/", trace_dns: bool = False) -> L7Result:
|
|
@@ -169,7 +169,7 @@ class MCPAttacker:
|
|
|
169
169
|
test_headers = {
|
|
170
170
|
"Content-Type": "application/json",
|
|
171
171
|
"Accept": "application/json, text/event-stream",
|
|
172
|
-
"User-Agent": "offsec-ai/2.0.
|
|
172
|
+
"User-Agent": "offsec-ai/2.0.1",
|
|
173
173
|
**probe.get("headers", {}),
|
|
174
174
|
}
|
|
175
175
|
triggered = False
|
|
@@ -233,7 +233,7 @@ class MCPAttacker:
|
|
|
233
233
|
async with httpx.AsyncClient(
|
|
234
234
|
headers={"Content-Type": "application/json",
|
|
235
235
|
"Accept": "application/json, text/event-stream",
|
|
236
|
-
"User-Agent": "offsec-ai/2.0.
|
|
236
|
+
"User-Agent": "offsec-ai/2.0.1", **headers},
|
|
237
237
|
timeout=timeout,
|
|
238
238
|
) as client:
|
|
239
239
|
resp = await client.post(target, json=payload)
|
|
@@ -295,7 +295,7 @@ class MCPAttacker:
|
|
|
295
295
|
async with httpx.AsyncClient(
|
|
296
296
|
headers={"Content-Type": "application/json",
|
|
297
297
|
"Accept": "application/json, text/event-stream",
|
|
298
|
-
"User-Agent": "offsec-ai/2.0.
|
|
298
|
+
"User-Agent": "offsec-ai/2.0.1", **headers},
|
|
299
299
|
timeout=timeout,
|
|
300
300
|
) as client:
|
|
301
301
|
resp = await client.post(target, json=payload)
|
|
@@ -356,7 +356,7 @@ class MCPAttacker:
|
|
|
356
356
|
async with httpx.AsyncClient(
|
|
357
357
|
headers={"Content-Type": "application/json",
|
|
358
358
|
"Accept": "application/json, text/event-stream",
|
|
359
|
-
"User-Agent": "offsec-ai/2.0.
|
|
359
|
+
"User-Agent": "offsec-ai/2.0.1", **headers},
|
|
360
360
|
timeout=timeout,
|
|
361
361
|
) as client:
|
|
362
362
|
resp = await client.post(target, json=payload)
|
|
@@ -97,7 +97,7 @@ class MCPScanner:
|
|
|
97
97
|
headers={
|
|
98
98
|
"Content-Type": "application/json",
|
|
99
99
|
"Accept": "application/json, text/event-stream",
|
|
100
|
-
"User-Agent": "offsec-ai/2.0.
|
|
100
|
+
"User-Agent": "offsec-ai/2.0.1",
|
|
101
101
|
**self.headers,
|
|
102
102
|
},
|
|
103
103
|
timeout=self.timeout,
|
|
@@ -189,7 +189,7 @@ class MCPScanner:
|
|
|
189
189
|
|
|
190
190
|
# Try without any auth header
|
|
191
191
|
no_auth_client = httpx.AsyncClient(
|
|
192
|
-
headers={"Content-Type": "application/json", "Accept": "application/json, text/event-stream", "User-Agent": "offsec-ai/2.0.
|
|
192
|
+
headers={"Content-Type": "application/json", "Accept": "application/json, text/event-stream", "User-Agent": "offsec-ai/2.0.1"},
|
|
193
193
|
timeout=self.timeout,
|
|
194
194
|
)
|
|
195
195
|
async with no_auth_client:
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Tests for mTLS models and CLI commands."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_imports():
|
|
7
|
+
"""All mTLS modules import without error."""
|
|
8
|
+
from offsec_ai.models.mtls_result import BatchMTLSResult, CertificateInfo, MTLSResult # noqa: F401
|
|
9
|
+
from offsec_ai.core.mtls_checker import MTLSChecker # noqa: F401
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_certificate_info_model():
|
|
13
|
+
"""CertificateInfo model fields are created correctly."""
|
|
14
|
+
from offsec_ai.models.mtls_result import CertificateInfo
|
|
15
|
+
|
|
16
|
+
cert = CertificateInfo(
|
|
17
|
+
subject="CN=test.example.com",
|
|
18
|
+
issuer="CN=Test CA",
|
|
19
|
+
version=3,
|
|
20
|
+
serial_number="12345",
|
|
21
|
+
not_valid_before="2024-01-01T00:00:00",
|
|
22
|
+
not_valid_after="2025-01-01T00:00:00",
|
|
23
|
+
signature_algorithm="sha256WithRSAEncryption",
|
|
24
|
+
key_algorithm="RSAPublicKey",
|
|
25
|
+
key_size=2048,
|
|
26
|
+
san_dns_names=["test.example.com", "*.example.com"],
|
|
27
|
+
san_ip_addresses=["192.168.1.1"],
|
|
28
|
+
is_ca=False,
|
|
29
|
+
is_self_signed=False,
|
|
30
|
+
fingerprint_sha256="abcd1234...",
|
|
31
|
+
)
|
|
32
|
+
assert cert.subject == "CN=test.example.com"
|
|
33
|
+
assert cert.key_size == 2048
|
|
34
|
+
assert "test.example.com" in cert.san_dns_names
|
|
35
|
+
assert cert.is_ca is False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_mtls_result_model():
|
|
39
|
+
"""MTLSResult is created, fields are accessible, and serializes to JSON."""
|
|
40
|
+
from offsec_ai.models.mtls_result import CertificateInfo, MTLSResult
|
|
41
|
+
|
|
42
|
+
cert = CertificateInfo(
|
|
43
|
+
subject="CN=test.example.com",
|
|
44
|
+
issuer="CN=Test CA",
|
|
45
|
+
version=3,
|
|
46
|
+
serial_number="12345",
|
|
47
|
+
not_valid_before="2024-01-01T00:00:00",
|
|
48
|
+
not_valid_after="2025-01-01T00:00:00",
|
|
49
|
+
signature_algorithm="sha256WithRSAEncryption",
|
|
50
|
+
key_algorithm="RSAPublicKey",
|
|
51
|
+
key_size=2048,
|
|
52
|
+
san_dns_names=["test.example.com"],
|
|
53
|
+
san_ip_addresses=[],
|
|
54
|
+
is_ca=False,
|
|
55
|
+
is_self_signed=False,
|
|
56
|
+
fingerprint_sha256="abcd1234...",
|
|
57
|
+
)
|
|
58
|
+
result = MTLSResult(
|
|
59
|
+
target="test.example.com",
|
|
60
|
+
port=443,
|
|
61
|
+
supports_mtls=True,
|
|
62
|
+
requires_client_cert=False,
|
|
63
|
+
server_cert_info=cert,
|
|
64
|
+
client_cert_requested=True,
|
|
65
|
+
handshake_successful=False,
|
|
66
|
+
error_message=None,
|
|
67
|
+
cipher_suite="TLS_AES_256_GCM_SHA384",
|
|
68
|
+
tls_version="TLSv1.3",
|
|
69
|
+
verification_mode="default",
|
|
70
|
+
ca_bundle_path="/etc/ssl/certs/ca-certificates.crt",
|
|
71
|
+
timestamp=datetime.now().isoformat(),
|
|
72
|
+
)
|
|
73
|
+
assert result.target == "test.example.com"
|
|
74
|
+
assert result.port == 443
|
|
75
|
+
assert result.supports_mtls is True
|
|
76
|
+
assert result.server_cert_info.key_size == 2048
|
|
77
|
+
|
|
78
|
+
json_str = result.model_dump_json()
|
|
79
|
+
assert "test.example.com" in json_str
|
|
80
|
+
assert "TLSv1.3" in json_str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_cli_mtls_commands_exist():
|
|
84
|
+
"""mTLS CLI commands are registered and return help text."""
|
|
85
|
+
from click.testing import CliRunner
|
|
86
|
+
|
|
87
|
+
from offsec_ai.cli import main
|
|
88
|
+
|
|
89
|
+
runner = CliRunner()
|
|
90
|
+
|
|
91
|
+
result = runner.invoke(main, ["--help"])
|
|
92
|
+
assert result.exit_code == 0
|
|
93
|
+
assert "mtls-check" in result.output
|
|
94
|
+
|
|
95
|
+
result = runner.invoke(main, ["mtls-check", "--help"])
|
|
96
|
+
assert result.exit_code == 0
|
|
97
|
+
|
|
98
|
+
result = runner.invoke(main, ["mtls-gen-cert", "--help"])
|
|
99
|
+
assert result.exit_code == 0
|
|
100
|
+
|
|
101
|
+
result = runner.invoke(main, ["mtls-validate-cert", "--help"])
|
|
102
|
+
assert result.exit_code == 0
|