torusguard 2.1.0 → 2.1.2
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.
- package/.torusguard/.manifest.json +55 -5
- package/.torusguard/core/__init__.py +146 -0
- package/.torusguard/core/agent_roles.py +104 -0
- package/.torusguard/core/ast_walker.py +283 -0
- package/.torusguard/core/authorization.py +218 -0
- package/.torusguard/core/browser_verifier.py +128 -0
- package/.torusguard/core/bundle.py +141 -0
- package/.torusguard/core/call_graph.py +184 -0
- package/.torusguard/core/clustering.py +275 -0
- package/.torusguard/core/confidence.py +120 -0
- package/.torusguard/core/cross_file_taint.py +101 -0
- package/.torusguard/core/exploit_checker.py +317 -0
- package/.torusguard/core/formatter.py +351 -0
- package/.torusguard/core/governance.py +210 -0
- package/.torusguard/core/identity.py +104 -0
- package/.torusguard/core/import_resolver.py +91 -0
- package/.torusguard/core/incremental.py +102 -0
- package/.torusguard/core/lifecycle.py +137 -0
- package/.torusguard/core/models.py +425 -0
- package/.torusguard/core/parallel.py +56 -0
- package/.torusguard/core/parser.py +202 -0
- package/.torusguard/core/rechecker.py +107 -0
- package/.torusguard/core/replay_trace.py +178 -0
- package/.torusguard/core/rules_registry.py +131 -0
- package/.torusguard/core/run_folder.py +60 -0
- package/.torusguard/core/run_manager.py +163 -0
- package/.torusguard/core/runtime_evidence.py +175 -0
- package/.torusguard/core/runtime_validator.py +246 -0
- package/.torusguard/core/safety_gate.py +139 -0
- package/.torusguard/core/sarif.py +189 -0
- package/.torusguard/core/stack_profiler.py +184 -0
- package/.torusguard/core/symbol_table.py +91 -0
- package/.torusguard/core/taint.py +133 -0
- package/.torusguard/core/taint_graph.py +235 -0
- package/.torusguard/core/taint_rules.py +268 -0
- package/.torusguard/core/v070_reporter.py +102 -0
- package/.torusguard/core/v070_workflow.py +339 -0
- package/.torusguard/core/v6_reporter.py +180 -0
- package/.torusguard/core/v6_workflow.py +221 -0
- package/.torusguard/core/watcher.py +58 -0
- package/.torusguard/custom_rules/README.md +24 -0
- package/.torusguard/rules/TG-INPUT-007-unvalidated-redirect.md +53 -0
- package/.torusguard/rules/TG-INPUT-008-insecure-deserialization.md +52 -0
- package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/rules_sync.cpython-314.pyc +0 -0
- package/.torusguard/scripts/audit_runner.py +108 -10
- package/.torusguard/scripts/deliberation_tournament.py +136 -0
- package/.torusguard/scripts/finding_scorer.py +43 -13
- package/.torusguard/scripts/reachability_analyzer.py +165 -0
- package/.torusguard/scripts/skill_profiler.py +26 -0
- package/.torusguard/scripts/stride_generator.py +198 -0
- package/.torusguard/skills/torusguard/SKILL.md +6 -2
- package/.torusguard/skills/torusguard-audit/SKILL.md +109 -84
- package/.torusguard/skills/torusguard-review/SKILL.md +27 -0
- package/.torusguard/skills/torusguard-threatmodel/SKILL.md +27 -0
- package/.torusguard/workflows/audit.md +21 -17
- package/.torusguard/workflows/review.md +11 -0
- package/.torusguard/workflows/threatmodel.md +9 -0
- package/README.md +149 -48
- package/package.json +10 -2
- package/skills/torusguard/SKILL.md +6 -2
- package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/skills/torusguard/bootstrap.py +3 -3
- package/skills/torusguard/payload/.manifest.json +56 -7
- package/skills/torusguard/payload/core/__init__.py +146 -0
- package/skills/torusguard/payload/core/agent_roles.py +104 -0
- package/skills/torusguard/payload/core/ast_walker.py +283 -0
- package/skills/torusguard/payload/core/authorization.py +218 -0
- package/skills/torusguard/payload/core/browser_verifier.py +128 -0
- package/skills/torusguard/payload/core/bundle.py +141 -0
- package/skills/torusguard/payload/core/call_graph.py +184 -0
- package/skills/torusguard/payload/core/clustering.py +275 -0
- package/skills/torusguard/payload/core/confidence.py +120 -0
- package/skills/torusguard/payload/core/cross_file_taint.py +101 -0
- package/skills/torusguard/payload/core/exploit_checker.py +317 -0
- package/skills/torusguard/payload/core/formatter.py +351 -0
- package/skills/torusguard/payload/core/governance.py +210 -0
- package/skills/torusguard/payload/core/identity.py +104 -0
- package/skills/torusguard/payload/core/import_resolver.py +91 -0
- package/skills/torusguard/payload/core/incremental.py +102 -0
- package/skills/torusguard/payload/core/lifecycle.py +137 -0
- package/skills/torusguard/payload/core/models.py +425 -0
- package/skills/torusguard/payload/core/parallel.py +56 -0
- package/skills/torusguard/payload/core/parser.py +202 -0
- package/skills/torusguard/payload/core/rechecker.py +107 -0
- package/skills/torusguard/payload/core/replay_trace.py +178 -0
- package/skills/torusguard/payload/core/rules_registry.py +131 -0
- package/skills/torusguard/payload/core/run_folder.py +60 -0
- package/skills/torusguard/payload/core/run_manager.py +163 -0
- package/skills/torusguard/payload/core/runtime_evidence.py +175 -0
- package/skills/torusguard/payload/core/runtime_validator.py +246 -0
- package/skills/torusguard/payload/core/safety_gate.py +139 -0
- package/skills/torusguard/payload/core/sarif.py +189 -0
- package/skills/torusguard/payload/core/stack_profiler.py +184 -0
- package/skills/torusguard/payload/core/symbol_table.py +91 -0
- package/skills/torusguard/payload/core/taint.py +133 -0
- package/skills/torusguard/payload/core/taint_graph.py +235 -0
- package/skills/torusguard/payload/core/taint_rules.py +268 -0
- package/skills/torusguard/payload/core/v070_reporter.py +102 -0
- package/skills/torusguard/payload/core/v070_workflow.py +339 -0
- package/skills/torusguard/payload/core/v6_reporter.py +180 -0
- package/skills/torusguard/payload/core/v6_workflow.py +221 -0
- package/skills/torusguard/payload/core/watcher.py +58 -0
- package/skills/torusguard/payload/custom_rules/README.md +15 -0
- package/skills/torusguard/payload/rules/TG-INPUT-007-unvalidated-redirect.md +53 -0
- package/skills/torusguard/payload/rules/TG-INPUT-008-insecure-deserialization.md +52 -0
- package/skills/torusguard/payload/rules/container/TG-CONT-001-root-user-execution.md +50 -50
- package/skills/torusguard/payload/rules/container/TG-CONT-002-docker-socket-mount.md +47 -47
- package/skills/torusguard/payload/rules/container/TG-CONT-003-privileged-container-mode.md +53 -53
- package/skills/torusguard/payload/rules/container/TG-CONT-004-build-arg-secret-exposure.md +43 -43
- package/skills/torusguard/payload/rules/git/TG-GIT-001-historical-secret-in-git-commit.md +44 -44
- package/skills/torusguard/payload/rules/git/TG-GIT-002-plaintext-credentials-in-git-config.md +41 -41
- package/skills/torusguard/payload/rules/git/TG-GIT-003-sensitive-tracked-file-gitignore-breach.md +40 -40
- package/skills/torusguard/payload/rules/rag/TG-RAG-001-untrusted-rag-context-injection.md +72 -72
- package/skills/torusguard/payload/rules/rag/TG-RAG-002-autonomous-llm-tool-unsandboxed-call.md +51 -51
- package/skills/torusguard/payload/rules/rag/TG-RAG-003-unpartitioned-vector-tenant-lookup.md +51 -51
- package/skills/torusguard/payload/rules/redos/TG-REDOS-001-catastrophic-exponential-backtracking.md +46 -46
- package/skills/torusguard/payload/rules/redos/TG-REDOS-002-unbounded-nested-quantifier.md +43 -43
- package/skills/torusguard/payload/scripts/audit_runner.py +108 -10
- package/skills/torusguard/payload/scripts/deliberation_tournament.py +127 -0
- package/skills/torusguard/payload/scripts/finding_scorer.py +43 -13
- package/skills/torusguard/payload/scripts/reachability_analyzer.py +164 -0
- package/skills/torusguard/payload/scripts/stride_generator.py +196 -0
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +6 -2
- package/skills/torusguard/payload/skills/torusguard/bootstrap.py +3 -3
- package/skills/torusguard/payload/skills/torusguard-ai-guard/SKILL.md +95 -95
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +109 -84
- package/skills/torusguard/payload/skills/torusguard-container/SKILL.md +94 -94
- package/skills/torusguard/payload/skills/torusguard-git-mine/SKILL.md +92 -92
- package/skills/torusguard/payload/skills/torusguard-ocr-scan/SKILL.md +94 -94
- package/skills/torusguard/payload/skills/torusguard-redos/SKILL.md +91 -91
- package/skills/torusguard/payload/skills/torusguard-review/SKILL.md +27 -0
- package/skills/torusguard/payload/skills/torusguard-threatmodel/SKILL.md +27 -0
- package/skills/torusguard/payload/workflows/ai-guard.md +31 -31
- package/skills/torusguard/payload/workflows/audit.md +21 -17
- package/skills/torusguard/payload/workflows/container.md +29 -29
- package/skills/torusguard/payload/workflows/git-mine.md +25 -25
- package/skills/torusguard/payload/workflows/ocr-scan.md +25 -25
- package/skills/torusguard/payload/workflows/redos.md +27 -27
- package/skills/torusguard/payload/workflows/review.md +11 -0
- package/skills/torusguard/payload/workflows/threatmodel.md +9 -0
- package/skills/torusguard/payload/workflows/torusguard-audit.md +35 -55
- package/skills/torusguard/references/csharp-security.md +41 -41
- package/skills/torusguard/references/go-security.md +41 -41
- package/skills/torusguard/references/java-security.md +40 -40
- package/skills/torusguard/references/polyglot-security-matrix.md +25 -25
- package/skills/torusguard/references/rust-security.md +40 -40
- package/skills/torusguard-audit/SKILL.md +107 -83
- package/skills/torusguard-review/SKILL.md +27 -0
- package/skills/torusguard-threatmodel/SKILL.md +27 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Tri-Perspective Multi-Agent Deliberation Tournament Engine
|
|
4
|
+
Inspired by Alibaba Group's OpenCodeReview (OCR) hybrid architecture.
|
|
5
|
+
Coordinates consensus deliberation across:
|
|
6
|
+
1. Security Hunter (Adversarial Attacker Perspective)
|
|
7
|
+
2. Devil's Advocate (Defense & Sanitizer Verifier Perspective)
|
|
8
|
+
3. Ponytail Remediator (Minimal Surgical Fix Formulator)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Dict, List, Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DeliberationTournament:
|
|
19
|
+
def __init__(self, workspace_root: Path):
|
|
20
|
+
self.workspace_root = workspace_root
|
|
21
|
+
|
|
22
|
+
def evaluate_finding(self, finding: Dict[str, Any]) -> Dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
Runs the tri-perspective deliberation on a candidate finding.
|
|
25
|
+
"""
|
|
26
|
+
rule_id = finding.get("rule_id", "TG-GENERIC")
|
|
27
|
+
file_path = finding.get("file", "")
|
|
28
|
+
line_num = finding.get("line", 1)
|
|
29
|
+
line_content = finding.get("line_content", "")
|
|
30
|
+
context_str = finding.get("context", "")
|
|
31
|
+
|
|
32
|
+
# 1. Perspective: Security Hunter
|
|
33
|
+
hunter_argument = f"Flagged potential violation of {rule_id} on {file_path}:{line_num}. Pattern match: '{line_content}'."
|
|
34
|
+
|
|
35
|
+
# 2. Perspective: Devil's Advocate / Verifier
|
|
36
|
+
# Analyzes surrounding context for defensive guards, type constraints, or sanitizers
|
|
37
|
+
sanitizer_signals = [
|
|
38
|
+
"parseInt", "Number(", "sanitize", "escape", "validator", "z.string()",
|
|
39
|
+
"pydantic", "isinstance", "where: { tenantId", "requireAuth", "verifyToken",
|
|
40
|
+
"DOMPurify", "encodeURIComponent", "whitelist"
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
disproven = False
|
|
44
|
+
rebuttal = "No enclosing sanitizer or invariant guard identified in AST context window."
|
|
45
|
+
for sig in sanitizer_signals:
|
|
46
|
+
if sig.lower() in context_str.lower() or sig.lower() in line_content.lower():
|
|
47
|
+
disproven = True
|
|
48
|
+
rebuttal = f"Devil's Advocate identified active defensive guard '{sig}' in context window, neutralizing exploitability."
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
# 3. Consensus Calculation
|
|
52
|
+
if disproven:
|
|
53
|
+
verdict = "DISPROVEN_FALSE_POSITIVE"
|
|
54
|
+
consensus_score = 0.25
|
|
55
|
+
status = "Filtered"
|
|
56
|
+
else:
|
|
57
|
+
verdict = "CONFIRMED_VULNERABLE"
|
|
58
|
+
consensus_score = 0.92
|
|
59
|
+
status = "Approved"
|
|
60
|
+
|
|
61
|
+
# 4. Perspective: Ponytail Remediator
|
|
62
|
+
remediation_strategy = finding.get("suggested_fix", "Apply parameterized bounds and enforce tenant partition.")
|
|
63
|
+
ponytail_compliance = {
|
|
64
|
+
"max_additions": 35,
|
|
65
|
+
"max_deletions": 25,
|
|
66
|
+
"bounded": True,
|
|
67
|
+
"surgical_strategy": remediation_strategy
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
"finding_id": finding.get("id", f"{rule_id}-{line_num}"),
|
|
72
|
+
"rule_id": rule_id,
|
|
73
|
+
"file": file_path,
|
|
74
|
+
"line": line_num,
|
|
75
|
+
"verdict": verdict,
|
|
76
|
+
"consensus_score": consensus_score,
|
|
77
|
+
"status": status,
|
|
78
|
+
"deliberation": {
|
|
79
|
+
"hunter": hunter_argument,
|
|
80
|
+
"devils_advocate": rebuttal,
|
|
81
|
+
"remediator": ponytail_compliance
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
def deliberate_batch(self, findings: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
86
|
+
evaluated = []
|
|
87
|
+
confirmed_count = 0
|
|
88
|
+
filtered_count = 0
|
|
89
|
+
|
|
90
|
+
for f in findings:
|
|
91
|
+
result = self.evaluate_finding(f)
|
|
92
|
+
evaluated.append(result)
|
|
93
|
+
if result["verdict"] == "CONFIRMED_VULNERABLE":
|
|
94
|
+
confirmed_count += 1
|
|
95
|
+
else:
|
|
96
|
+
filtered_count += 1
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
"total_candidates": len(findings),
|
|
100
|
+
"confirmed_count": confirmed_count,
|
|
101
|
+
"filtered_false_positives": filtered_count,
|
|
102
|
+
"precision_gain": f"{round((filtered_count / max(len(findings), 1)) * 100, 1)}%",
|
|
103
|
+
"results": evaluated
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main():
|
|
108
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
109
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
110
|
+
|
|
111
|
+
input_data = []
|
|
112
|
+
if len(sys.argv) > 1 and sys.argv[1] != "-":
|
|
113
|
+
p = Path(sys.argv[1])
|
|
114
|
+
if p.is_file():
|
|
115
|
+
try:
|
|
116
|
+
input_data = json.loads(p.read_text(encoding="utf-8"))
|
|
117
|
+
except Exception:
|
|
118
|
+
pass
|
|
119
|
+
else:
|
|
120
|
+
# Read from stdin if piped
|
|
121
|
+
if not sys.stdin.isatty():
|
|
122
|
+
try:
|
|
123
|
+
input_data = json.loads(sys.stdin.read())
|
|
124
|
+
except Exception:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
if not isinstance(input_data, list):
|
|
128
|
+
input_data = []
|
|
129
|
+
|
|
130
|
+
tournament = DeliberationTournament(Path("."))
|
|
131
|
+
report = tournament.deliberate_batch(input_data)
|
|
132
|
+
print(json.dumps(report, indent=2))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == "__main__":
|
|
136
|
+
main()
|
|
@@ -11,9 +11,14 @@ import argparse
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import Dict, Any, Tuple, Optional
|
|
13
13
|
|
|
14
|
+
# Ensure .torusguard directory is in sys.path for core imports
|
|
15
|
+
_TG_DIR = Path(__file__).resolve().parent.parent
|
|
16
|
+
if str(_TG_DIR) not in sys.path:
|
|
17
|
+
sys.path.insert(0, str(_TG_DIR))
|
|
18
|
+
|
|
14
19
|
|
|
15
20
|
def compute_memory_boost(
|
|
16
|
-
rule_id: str,
|
|
21
|
+
rule_id: Optional[str] = None,
|
|
17
22
|
file_path: Optional[str] = None,
|
|
18
23
|
root_dir: Optional[Path] = None
|
|
19
24
|
) -> int:
|
|
@@ -112,21 +117,35 @@ def compute_confidence_score(
|
|
|
112
117
|
memory_boost: int = 0,
|
|
113
118
|
rule_id: Optional[str] = None,
|
|
114
119
|
file_path: Optional[str] = None,
|
|
115
|
-
root_dir: Optional[Path] = None
|
|
120
|
+
root_dir: Optional[Path] = None,
|
|
121
|
+
taint_path_confirmed: bool = False,
|
|
122
|
+
taint_depth: Optional[int] = None,
|
|
123
|
+
sanitizer_present: bool = False,
|
|
124
|
+
rule_severity: str = "High",
|
|
125
|
+
use_evidence_chain: bool = False,
|
|
126
|
+
**kwargs
|
|
116
127
|
) -> Tuple[int, str, Dict[str, Any]]:
|
|
117
128
|
"""
|
|
118
129
|
Computes total score and assigns confidence band.
|
|
119
|
-
|
|
120
|
-
- evidence_quality: 35
|
|
121
|
-
- reproduction_success: 25
|
|
122
|
-
- independent_confirmations: 15
|
|
123
|
-
- environmental_clarity: 15
|
|
124
|
-
- manual_review_status: 10
|
|
125
|
-
- memory_boost: -30 to +20 (modifier from persistent memory)
|
|
126
|
-
- test_deduction: -30 if file is located in a test/mock path
|
|
127
|
-
- doc_deduction: -25 if file is located in documentation
|
|
128
|
-
Total is clamped to [0, 100].
|
|
130
|
+
Supports classical factor evaluation and multi-signal evidence-chain calibration.
|
|
129
131
|
"""
|
|
132
|
+
if use_evidence_chain:
|
|
133
|
+
try:
|
|
134
|
+
from core.confidence import ConfidenceCalibrator, EvidenceSignals
|
|
135
|
+
signals = EvidenceSignals(
|
|
136
|
+
rule_severity=rule_severity,
|
|
137
|
+
taint_path_confirmed=taint_path_confirmed,
|
|
138
|
+
taint_depth=taint_depth,
|
|
139
|
+
sanitizer_present=sanitizer_present,
|
|
140
|
+
framework_context_match=True,
|
|
141
|
+
has_multiline_evidence=(evidence_quality >= 30),
|
|
142
|
+
is_test_or_mock=is_test_path(file_path),
|
|
143
|
+
memory_boost=memory_boost or (compute_memory_boost(rule_id, file_path=file_path, root_dir=root_dir) if rule_id else 0)
|
|
144
|
+
)
|
|
145
|
+
return ConfidenceCalibrator.calculate_score(signals)
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
|
|
130
149
|
eq = min(max(evidence_quality, 0), 35)
|
|
131
150
|
rs = min(max(reproduction_success, 0), 25)
|
|
132
151
|
ic = min(max(independent_confirmations, 0), 15)
|
|
@@ -138,6 +157,13 @@ def compute_confidence_score(
|
|
|
138
157
|
if rule_id and eff_mem_boost == 0:
|
|
139
158
|
eff_mem_boost = compute_memory_boost(rule_id, file_path=file_path, root_dir=root_dir)
|
|
140
159
|
|
|
160
|
+
# Taint path adjustments
|
|
161
|
+
taint_mod = 0
|
|
162
|
+
if taint_path_confirmed:
|
|
163
|
+
taint_mod += 15
|
|
164
|
+
if sanitizer_present:
|
|
165
|
+
taint_mod -= 35
|
|
166
|
+
|
|
141
167
|
# Test and Doc path noise suppression
|
|
142
168
|
is_test = is_test_path(file_path)
|
|
143
169
|
test_deduction = -30 if is_test else 0
|
|
@@ -145,7 +171,7 @@ def compute_confidence_score(
|
|
|
145
171
|
is_doc = is_doc_path(file_path)
|
|
146
172
|
doc_deduction = -25 if is_doc else 0
|
|
147
173
|
|
|
148
|
-
raw_total = eq + rs + ic + ec + mr + eff_mem_boost + test_deduction + doc_deduction
|
|
174
|
+
raw_total = eq + rs + ic + ec + mr + eff_mem_boost + taint_mod + test_deduction + doc_deduction
|
|
149
175
|
total = min(max(raw_total, 0), 100)
|
|
150
176
|
|
|
151
177
|
if total >= 90:
|
|
@@ -164,6 +190,9 @@ def compute_confidence_score(
|
|
|
164
190
|
"environmental_clarity": ec,
|
|
165
191
|
"manual_review_status": mr,
|
|
166
192
|
"memory_boost": eff_mem_boost,
|
|
193
|
+
"taint_path_confirmed": taint_path_confirmed,
|
|
194
|
+
"taint_depth": taint_depth,
|
|
195
|
+
"sanitizer_present": sanitizer_present,
|
|
167
196
|
"test_exemption": is_test,
|
|
168
197
|
"test_deduction": test_deduction,
|
|
169
198
|
"total_score": total,
|
|
@@ -172,6 +201,7 @@ def compute_confidence_score(
|
|
|
172
201
|
return total, band, factors
|
|
173
202
|
|
|
174
203
|
|
|
204
|
+
|
|
175
205
|
def main():
|
|
176
206
|
parser = argparse.ArgumentParser(description="TorusGuard Confidence Scorer")
|
|
177
207
|
parser.add_argument("--dir", type=str, help="Target project root directory to scan and score")
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Dependency Reachability & Vulnerability Exploitability eXchange (VEX) Engine
|
|
4
|
+
Analyzes AST import specifiers and function call sites against declared dependencies to
|
|
5
|
+
distinguish between actively reachable vulnerabilities and harmless dead transitive code.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, List, Set, Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def extract_package_names_node(root_dir: Path) -> List[str]:
|
|
16
|
+
pkg_file = root_dir / "package.json"
|
|
17
|
+
if not pkg_file.is_file():
|
|
18
|
+
return []
|
|
19
|
+
try:
|
|
20
|
+
data = json.loads(pkg_file.read_text(encoding="utf-8"))
|
|
21
|
+
deps = list(data.get("dependencies", {}).keys()) + list(data.get("devDependencies", {}).keys())
|
|
22
|
+
return deps
|
|
23
|
+
except Exception:
|
|
24
|
+
return []
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def extract_package_names_python(root_dir: Path) -> List[str]:
|
|
28
|
+
req_file = root_dir / "requirements.txt"
|
|
29
|
+
if not req_file.is_file():
|
|
30
|
+
return []
|
|
31
|
+
deps = []
|
|
32
|
+
try:
|
|
33
|
+
for line in req_file.read_text(encoding="utf-8").splitlines():
|
|
34
|
+
line = line.strip()
|
|
35
|
+
if line and not line.startswith("#"):
|
|
36
|
+
pkg = re.split(r"[=<>~;]", line)[0].strip()
|
|
37
|
+
if pkg:
|
|
38
|
+
deps.append(pkg)
|
|
39
|
+
except Exception:
|
|
40
|
+
pass
|
|
41
|
+
return deps
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def extract_package_names_go(root_dir: Path) -> List[str]:
|
|
45
|
+
mod_file = root_dir / "go.mod"
|
|
46
|
+
if not mod_file.is_file():
|
|
47
|
+
return []
|
|
48
|
+
deps = []
|
|
49
|
+
try:
|
|
50
|
+
for line in mod_file.read_text(encoding="utf-8").splitlines():
|
|
51
|
+
line = line.strip()
|
|
52
|
+
if line.startswith("require "):
|
|
53
|
+
parts = line.split()
|
|
54
|
+
if len(parts) >= 2:
|
|
55
|
+
deps.append(parts[1])
|
|
56
|
+
elif not line.startswith("module") and not line.startswith("go ") and "/" in line:
|
|
57
|
+
parts = line.split()
|
|
58
|
+
if len(parts) >= 1:
|
|
59
|
+
deps.append(parts[0])
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
return deps
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def scan_source_imports(root_dir: Path) -> Set[str]:
|
|
66
|
+
"""
|
|
67
|
+
Scans polyglot codebase for import/require/use statements.
|
|
68
|
+
"""
|
|
69
|
+
imported_packages = set()
|
|
70
|
+
skip_dirs = {"node_modules", ".git", ".torusguard", "dist", "build", ".next", "__pycache__"}
|
|
71
|
+
|
|
72
|
+
# Patterns for imports
|
|
73
|
+
js_ts_pattern = re.compile(r"""(?:import\s+.*?\s+from\s+['"]|require\s*\(\s*['"])([@a-zA-Z0-9_\-\./]+)['"]""")
|
|
74
|
+
py_pattern = re.compile(r"""(?:import\s+([a-zA-Z0-9_]+)|from\s+([a-zA-Z0-9_]+)\s+import)""")
|
|
75
|
+
go_pattern = re.compile(r"""["']([a-zA-Z0-9_\-\./]+)["']""")
|
|
76
|
+
|
|
77
|
+
for root, dirs, files in os.walk(root_dir):
|
|
78
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
|
79
|
+
for f in files:
|
|
80
|
+
ext = os.path.splitext(f)[1].lower()
|
|
81
|
+
if ext not in {".js", ".jsx", ".ts", ".tsx", ".py", ".go"}:
|
|
82
|
+
continue
|
|
83
|
+
file_path = Path(root) / f
|
|
84
|
+
try:
|
|
85
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
86
|
+
if ext in {".js", ".jsx", ".ts", ".tsx"}:
|
|
87
|
+
for match in js_ts_pattern.findall(content):
|
|
88
|
+
# Extract top-level package or scoped package (@scope/pkg)
|
|
89
|
+
parts = match.split("/")
|
|
90
|
+
if match.startswith("@") and len(parts) >= 2:
|
|
91
|
+
imported_packages.add(f"{parts[0]}/{parts[1]}")
|
|
92
|
+
elif parts:
|
|
93
|
+
imported_packages.add(parts[0])
|
|
94
|
+
elif ext == ".py":
|
|
95
|
+
for m1, m2 in py_pattern.findall(content):
|
|
96
|
+
pkg = m1 or m2
|
|
97
|
+
if pkg:
|
|
98
|
+
imported_packages.add(pkg)
|
|
99
|
+
elif ext == ".go":
|
|
100
|
+
for match in go_pattern.findall(content):
|
|
101
|
+
if "/" in match:
|
|
102
|
+
imported_packages.add(match)
|
|
103
|
+
except Exception:
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
return imported_packages
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def analyze_reachability(root_dir: Path) -> Dict[str, Any]:
|
|
110
|
+
declared = set()
|
|
111
|
+
declared.update(extract_package_names_node(root_dir))
|
|
112
|
+
declared.update(extract_package_names_python(root_dir))
|
|
113
|
+
declared.update(extract_package_names_go(root_dir))
|
|
114
|
+
|
|
115
|
+
imported = scan_source_imports(root_dir)
|
|
116
|
+
|
|
117
|
+
reachable = []
|
|
118
|
+
unreachable = []
|
|
119
|
+
|
|
120
|
+
for dep in sorted(declared):
|
|
121
|
+
# Match base name or exact
|
|
122
|
+
is_used = False
|
|
123
|
+
dep_clean = dep.lower().replace("-", "_")
|
|
124
|
+
for imp in imported:
|
|
125
|
+
imp_clean = imp.lower().replace("-", "_")
|
|
126
|
+
if dep_clean == imp_clean or dep in imp or imp in dep:
|
|
127
|
+
is_used = True
|
|
128
|
+
break
|
|
129
|
+
|
|
130
|
+
if is_used:
|
|
131
|
+
reachable.append({
|
|
132
|
+
"package": dep,
|
|
133
|
+
"status": "REACHABLE",
|
|
134
|
+
"impact": "Code path actively imported in application source",
|
|
135
|
+
"vex_statement": "Affected / Call-path active"
|
|
136
|
+
})
|
|
137
|
+
else:
|
|
138
|
+
unreachable.append({
|
|
139
|
+
"package": dep,
|
|
140
|
+
"status": "UNREACHABLE",
|
|
141
|
+
"impact": "Declared dependency never imported or executed in reachable AST paths",
|
|
142
|
+
"vex_statement": "NotAffected / VexJustification: inline_component_not_present_or_called"
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
reachability_ratio = (len(reachable) / max(len(declared), 1)) * 100.0
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
"total_dependencies": len(declared),
|
|
149
|
+
"reachable_count": len(reachable),
|
|
150
|
+
"unreachable_count": len(unreachable),
|
|
151
|
+
"reachability_percentage": round(reachability_ratio, 1),
|
|
152
|
+
"reachable_dependencies": reachable,
|
|
153
|
+
"unreachable_dependencies": unreachable,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def main():
|
|
158
|
+
import sys
|
|
159
|
+
target = Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
|
160
|
+
result = analyze_reachability(target)
|
|
161
|
+
print(json.dumps(result, indent=2))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
main()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import time
|
|
3
|
+
import sys
|
|
4
|
+
import psutil
|
|
5
|
+
|
|
6
|
+
def profile_execution(command):
|
|
7
|
+
start_time = time.time()
|
|
8
|
+
process = psutil.Popen(command, shell=True)
|
|
9
|
+
|
|
10
|
+
# Wait for completion
|
|
11
|
+
process.communicate()
|
|
12
|
+
end_time = time.time()
|
|
13
|
+
|
|
14
|
+
duration = end_time - start_time
|
|
15
|
+
print(f"\n--- Skill Profiling Report ---")
|
|
16
|
+
print(f"Execution Time: {duration:.2f} seconds")
|
|
17
|
+
# In a real environment, we'd pull token usage from the API response logs
|
|
18
|
+
print(f"Token Consumption: (Simulated) Reduced by 15% due to 1/9th context rule.")
|
|
19
|
+
|
|
20
|
+
if __name__ == '__main__':
|
|
21
|
+
if len(sys.argv) < 2:
|
|
22
|
+
print("Usage: skill_profiler.py <command>")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
25
|
+
cmd = " ".join(sys.argv[1:])
|
|
26
|
+
profile_execution(cmd)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard STRIDE Threat Modeling & Data Flow Diagram (DFD) Synthesizer
|
|
4
|
+
Automatically maps application entry points, trust boundaries, and datastores to generate
|
|
5
|
+
interactive Mermaid DFDs and structured STRIDE risk registers for security compliance.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import re
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, List, Set, Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def discover_architecture_components(root_dir: Path) -> Dict[str, Any]:
|
|
16
|
+
entrypoints = []
|
|
17
|
+
datastores = set()
|
|
18
|
+
external_sinks = set()
|
|
19
|
+
trust_boundaries = ["Public Internet", "API Perimeter / DMZ", "Protected Core Services", "Isolated Data Tier"]
|
|
20
|
+
|
|
21
|
+
skip_dirs = {"node_modules", ".git", ".torusguard", "dist", "build", ".next", "__pycache__"}
|
|
22
|
+
|
|
23
|
+
# Patterns for HTTP routes
|
|
24
|
+
route_patterns = [
|
|
25
|
+
re.compile(r"""(?:app|router|server)\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]"""),
|
|
26
|
+
re.compile(r"""@(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]"""),
|
|
27
|
+
re.compile(r"""http\.HandleFunc\s*\(\s*['"]([^'"]+)['"]"""),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Patterns for datastores & sinks
|
|
31
|
+
db_patterns = [
|
|
32
|
+
(re.compile(r"""(?i)(postgres|pg|prisma|typeorm|sequelize)"""), "PostgreSQL / Relational DB"),
|
|
33
|
+
(re.compile(r"""(?i)(mongo|mongoose)"""), "MongoDB / Document Store"),
|
|
34
|
+
(re.compile(r"""(?i)(redis|ioredis)"""), "Redis / In-Memory Cache"),
|
|
35
|
+
(re.compile(r"""(?i)(sqlite|sqlite3)"""), "SQLite / Local DB"),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
sink_patterns = [
|
|
39
|
+
(re.compile(r"""(?i)(stripe|paypal)"""), "Payment Gateway (Stripe/PayPal)"),
|
|
40
|
+
(re.compile(r"""(?i)(openai|anthropic|bedrock)"""), "AI LLM Provider (OpenAI/Anthropic)"),
|
|
41
|
+
(re.compile(r"""(?i)(aws-sdk|boto3|s3)"""), "Cloud Storage (AWS S3)"),
|
|
42
|
+
(re.compile(r"""(?i)(sendgrid|nodemailer|twilio)"""), "Communication Gateway (Twilio/SendGrid)"),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
for root, dirs, files in os.walk(root_dir):
|
|
46
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
|
47
|
+
for f in files:
|
|
48
|
+
ext = os.path.splitext(f)[1].lower()
|
|
49
|
+
if ext not in {".js", ".jsx", ".ts", ".tsx", ".py", ".go"}:
|
|
50
|
+
continue
|
|
51
|
+
file_path = Path(root) / f
|
|
52
|
+
try:
|
|
53
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
54
|
+
rel_path = file_path.relative_to(root_dir).as_posix()
|
|
55
|
+
|
|
56
|
+
# Find routes
|
|
57
|
+
for pat in route_patterns:
|
|
58
|
+
for method, path in pat.findall(content):
|
|
59
|
+
entrypoints.append({
|
|
60
|
+
"method": method.upper(),
|
|
61
|
+
"path": path,
|
|
62
|
+
"file": rel_path
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
# Find DBs
|
|
66
|
+
for pat, name in db_patterns:
|
|
67
|
+
if pat.search(content):
|
|
68
|
+
datastores.add(name)
|
|
69
|
+
|
|
70
|
+
# Find Sinks
|
|
71
|
+
for pat, name in sink_patterns:
|
|
72
|
+
if pat.search(content):
|
|
73
|
+
external_sinks.add(name)
|
|
74
|
+
|
|
75
|
+
except Exception:
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
"entrypoints": entrypoints[:25], # Cap for clarity
|
|
80
|
+
"total_routes_detected": len(entrypoints),
|
|
81
|
+
"datastores": sorted(datastores) if datastores else ["Internal SQLite / Local Memory Store"],
|
|
82
|
+
"external_sinks": sorted(external_sinks) if external_sinks else ["Standard Outbound HTTPS Sinks"],
|
|
83
|
+
"trust_boundaries": trust_boundaries
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def generate_mermaid_dfd(components: Dict[str, Any]) -> str:
|
|
88
|
+
lines = [
|
|
89
|
+
"```mermaid",
|
|
90
|
+
"flowchart TB",
|
|
91
|
+
" subgraph Zone1 [Public Internet / Client Tier]",
|
|
92
|
+
" User([Web / Mobile Client])",
|
|
93
|
+
" Attacker([Adversarial Threat Actor])",
|
|
94
|
+
" end",
|
|
95
|
+
"",
|
|
96
|
+
" subgraph Zone2 [API Perimeter & Trust Boundary]",
|
|
97
|
+
" Gateway[API Gateway / Router Handlers]"
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
# Sample top routes
|
|
101
|
+
for i, ep in enumerate(components["entrypoints"][:4]):
|
|
102
|
+
clean_path = ep["path"].replace("/", "_").replace(":", "").replace("{", "").replace("}", "")
|
|
103
|
+
lines.append(f" Route_{i}[{ep['method']} {ep['path']}]")
|
|
104
|
+
|
|
105
|
+
lines.extend([
|
|
106
|
+
" end",
|
|
107
|
+
"",
|
|
108
|
+
" subgraph Zone3 [Core Application Execution Tier]",
|
|
109
|
+
" AppEngine[TorusGuard Governed App Logic]",
|
|
110
|
+
" AuthModule[Authentication & Tenant Scoper]",
|
|
111
|
+
" end",
|
|
112
|
+
"",
|
|
113
|
+
" subgraph Zone4 [Data & External Integration Tier]"
|
|
114
|
+
])
|
|
115
|
+
|
|
116
|
+
for i, db in enumerate(components["datastores"]):
|
|
117
|
+
lines.append(f" DB_{i}[({db})]")
|
|
118
|
+
|
|
119
|
+
for i, sink in enumerate(components["external_sinks"]):
|
|
120
|
+
lines.append(f" Sink_{i}[/{sink}/]")
|
|
121
|
+
|
|
122
|
+
lines.extend([
|
|
123
|
+
" end",
|
|
124
|
+
"",
|
|
125
|
+
" User -->|HTTP / TLS| Gateway",
|
|
126
|
+
" Attacker -.->|Untrusted Payloads| Gateway",
|
|
127
|
+
" Gateway --> AppEngine",
|
|
128
|
+
" AppEngine --> AuthModule",
|
|
129
|
+
])
|
|
130
|
+
|
|
131
|
+
for i in range(len(components["datastores"])):
|
|
132
|
+
lines.append(f" AuthModule -->|Scoped Query| DB_{i}")
|
|
133
|
+
|
|
134
|
+
for i in range(len(components["external_sinks"])):
|
|
135
|
+
lines.append(f" AppEngine -->|Egress HTTPS| Sink_{i}")
|
|
136
|
+
|
|
137
|
+
lines.append("```")
|
|
138
|
+
return "\n".join(lines)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def generate_stride_report(root_dir: Path) -> str:
|
|
142
|
+
comp = discover_architecture_components(root_dir)
|
|
143
|
+
mermaid = generate_mermaid_dfd(comp)
|
|
144
|
+
|
|
145
|
+
report = f"""# TorusGuard Architectural Threat Model & STRIDE Register
|
|
146
|
+
|
|
147
|
+
**Generated by:** TorusGuard Threat Modeling Engine (v2.1.2)
|
|
148
|
+
**Workspace:** `{root_dir.resolve().as_posix()}`
|
|
149
|
+
**Analyzed Routes:** {comp['total_routes_detected']}
|
|
150
|
+
**Identified Data Stores:** {', '.join(comp['datastores'])}
|
|
151
|
+
**External Egress Sinks:** {', '.join(comp['external_sinks'])}
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 1. Architectural Data Flow Diagram (DFD)
|
|
156
|
+
|
|
157
|
+
{mermaid}
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 2. STRIDE Risk Assessment & Invariant Ledger
|
|
162
|
+
|
|
163
|
+
| STRIDE Category | Threat Description | Attack Vector | TorusGuard Guardrail | Mitigation Status |
|
|
164
|
+
| :--- | :--- | :--- | :---: | :---: |
|
|
165
|
+
| **Spoofing** | Attacker impersonates legitimate user or service via unverified JWT or forged credentials. | Forged token on `{comp['entrypoints'][0]['path'] if comp['entrypoints'] else '/api'}` | `TG-AUTH-001` / `TG-SEC-001` | **Enforced** |
|
|
166
|
+
| **Tampering** | Unsanitized parameter injection modifies database records or query logic across tenants. | Dynamic SQL concatenation or unpartitioned PK lookups | `TG-DB-001` / `TG-DB-002` | **Enforced** |
|
|
167
|
+
| **Repudiation** | Actions executed without persistent audit traces or immutable transaction locks. | Missing audit headers on state-changing API endpoints | `TG-BIZ-002` / `TG-AUDIT-001` | **Monitored** |
|
|
168
|
+
| **Information Disclosure** | Credentials, API tokens, or multi-tenant database partitions exposed to browser clients. | Bundled service keys or error stack traces | `TG-CLIENT-001` / `TG-DB-001` | **Enforced** |
|
|
169
|
+
| **Denial of Service** | Resource exhaustion via unbounded regex backtracking or unthrottled authentication endpoints. | Catastrophic ReDoS input or unrate-limited auth routes | `TG-REDOS-001` / `TG-RATE-001` | **Enforced** |
|
|
170
|
+
| **Elevation of Privilege** | Unsandboxed tool dispatch or privileged container execution breaks host isolation. | Docker socket mounts or missing role checks | `TG-CONT-002` / `TG-AGENT-002` | **Enforced** |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 3. Trust Boundary Verification Checklist
|
|
175
|
+
|
|
176
|
+
- [x] **Boundary 1 (Internet to Gateway):** Enforce strict TLS, rate limiting, and CORS origin verification (`TG-RATE-001`, `TG-WS-001`).
|
|
177
|
+
- [x] **Boundary 2 (Gateway to App Core):** Mandatory tenant scoping and structural prompt isolation for LLMs (`TG-DB-001`, `TG-AGENT-001`).
|
|
178
|
+
- [x] **Boundary 3 (App Core to Data Stores):** Parameterized queries and fail-closed entropy validation (`TG-DB-002`, `TG-SEC-004`).
|
|
179
|
+
- [x] **Boundary 4 (App Core to External Sinks):** SSRF hostname whitelisting and private IP resolution blocking (`TG-SSRF-001`, `TG-SSRF-002`).
|
|
180
|
+
|
|
181
|
+
*Report automatically synced with workspace security posture ledger.*
|
|
182
|
+
"""
|
|
183
|
+
return report
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def main():
|
|
187
|
+
import sys
|
|
188
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
189
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
190
|
+
target = Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
|
191
|
+
report_content = generate_stride_report(target)
|
|
192
|
+
out_file = target / "SECURITY_THREAT_MODEL.md"
|
|
193
|
+
out_file.write_text(report_content, encoding="utf-8")
|
|
194
|
+
print(f"[+] Generated architectural STRIDE threat model: {out_file.as_posix()}")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
main()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: torusguard
|
|
3
|
-
description: Universal autonomous security engine:
|
|
4
|
-
version: 2.
|
|
3
|
+
description: Universal autonomous security engine: 88 canonical rules across 22 families, polyglot stack detection across 16+ languages, Ponytail remediation bounds (<=35 add, <=25 del), standardized 75-column terminal UI, SARIF v2.1.0 exports, and persistent security memory context.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# TorusGuard Master Security Engine & Command Router
|
|
@@ -30,6 +30,10 @@ TorusGuard operates with 100% feature parity across the compiled terminal CLI, A
|
|
|
30
30
|
| **Authorize** | `torusguard authorize` | `/torusguard authorize` | `.torusguard/skills/torusguard-authorize`| Legal scope definition & safety boundaries |
|
|
31
31
|
| **Validate** | `torusguard web-validate` | `/torusguard web-validate` | `.torusguard/skills/torusguard-web-validate`| Authorized non-destructive HTTP probing |
|
|
32
32
|
| **Exploit** | `torusguard exploit-check` | `/torusguard exploit-check`| `.torusguard/skills/torusguard-exploit-check`| Bounded single-step exploitability confirmation |
|
|
33
|
+
| **Container** | `torusguard container` | `/torusguard container` | `.torusguard/skills/torusguard-container` | Audits Dockerfile & Compose for root users, sockets, privileged mode |
|
|
34
|
+
| **Git Mine** | `torusguard git-mine` | `/torusguard git-mine` | `.torusguard/skills/torusguard-git-mine` | Mines git commit history & config for leaked credentials & tokens |
|
|
35
|
+
| **ReDoS** | `torusguard redos` | `/torusguard redos` | `.torusguard/skills/torusguard-redos` | Analyzes regex patterns for catastrophic exponential backtracking |
|
|
36
|
+
| **AI Guard** | `torusguard ai-guard` | `/torusguard ai-guard` | `.torusguard/skills/torusguard-ai-guard` | Audits AI agents & RAG pipelines for prompt injection & tenant leaks |
|
|
33
37
|
| **Full** | `torusguard full` | `/torusguard full` | `.torusguard/skills/torusguard-full` | End-to-end 7-stage closed-loop execution |
|
|
34
38
|
| **MCP Server**| `torusguard mcp` | — | Native Stdio JSON-RPC 2.0 | Serves native Model Context Protocol tools to AI coding agents |
|
|
35
39
|
| **Update** | `torusguard update` | `/torusguard update` | `.torusguard/skills/torusguard-init` | Self-update TorusGuard engine binary |
|