0xray 4.0.36 → 4.0.38
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/.grok-plugin/plugin.json +1 -1
- package/.xray/features.json +1 -1
- package/dist/CHANGELOG.md +28 -0
- package/dist/analytics/emerging-pattern-detector.d.ts +12 -1
- package/dist/analytics/emerging-pattern-detector.js +37 -12
- package/dist/analytics/pattern-learning-engine.js +1 -9
- package/dist/analytics/predictive-analytics.js +51 -33
- package/dist/analytics/prompt-pattern-analyzer.d.ts +1 -0
- package/dist/analytics/prompt-pattern-analyzer.js +39 -20
- package/dist/analytics/routing-performance-analyzer.d.ts +2 -0
- package/dist/analytics/routing-performance-analyzer.js +89 -37
- package/dist/analytics/simple-pattern-analyzer.d.ts +4 -0
- package/dist/analytics/simple-pattern-analyzer.js +66 -28
- package/dist/architect/architect-tools.d.ts +3 -0
- package/dist/architect/architect-tools.js +22 -0
- package/dist/cli/commands/grok-install.js +1 -1
- package/dist/cli/commands/hermes-install.js +11 -5
- package/dist/cli/commands/openclaw-install.js +13 -7
- package/dist/cli/commands/opencode-install.js +7 -4
- package/dist/cli/commands/suit-monitor.d.ts +30 -0
- package/dist/cli/commands/suit-monitor.js +128 -0
- package/dist/cli/index.js +52 -15
- package/dist/cli/suit-pulse.d.ts +29 -0
- package/dist/cli/suit-pulse.js +270 -0
- package/dist/delegation/agent-delegator.d.ts +4 -2
- package/dist/delegation/agent-delegator.js +46 -27
- package/dist/delegation/agent-expertise.js +2 -1
- package/dist/delegation/analytics/outcome-tracker.d.ts +6 -0
- package/dist/delegation/analytics/outcome-tracker.js +17 -3
- package/dist/delegation/ast-code-parser.d.ts +5 -0
- package/dist/delegation/ast-code-parser.js +53 -48
- package/dist/delegation/codebase-context-analyzer.d.ts +3 -7
- package/dist/delegation/codebase-context-analyzer.js +188 -159
- package/dist/delegation/session-coordinator.js +3 -2
- package/dist/enforcement/loaders/codex-loader.js +18 -14
- package/dist/enforcement/validators/architecture-validators.js +115 -9
- package/dist/governance/codex-policy.service.d.ts +12 -2
- package/dist/governance/codex-policy.service.js +91 -16
- package/dist/integrations/grok/hooks/session-start.js +6 -6
- package/dist/integrations/hooks/goggles-pipeline.mjs +169 -28
- package/dist/integrations/hooks/goggles-planes.json +172 -8
- package/dist/integrations/hooks/plates.cjs +138 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +63 -5
- package/dist/integrations/hooks/write-home.cjs +59 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/architect-tools.server.d.ts +6 -0
- package/dist/mcps/architect-tools.server.js +19 -18
- package/dist/mcps/orchestrator/server.d.ts +4 -3
- package/dist/mcps/orchestrator/server.js +29 -17
- package/dist/memory-routing/lookup-cache.d.ts +8 -0
- package/dist/memory-routing/lookup-cache.js +72 -0
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +26 -0
- package/dist/memory-routing/provider-loader.js +3 -0
- package/dist/metrics/agent-metrics.d.ts +14 -5
- package/dist/metrics/agent-metrics.js +362 -224
- package/dist/nucleus/synthesis-consult-receipt.js +38 -16
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.d.ts +5 -0
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.js +9 -0
- package/dist/orchestrator/multi-agent-orchestration-coordinator.js +1 -2
- package/dist/orchestrator/orchestrator.js +1 -2
- package/dist/processors/implementations/agents-md-validation-processor.d.ts +0 -1
- package/dist/processors/implementations/agents-md-validation-processor.js +0 -11
- package/dist/processors/implementations/console-log-guard-processor.js +39 -50
- package/dist/processors/implementations/performance-budget-processor.d.ts +0 -5
- package/dist/processors/implementations/performance-budget-processor.js +29 -38
- package/dist/processors/implementations/storytelling-trigger-processor.d.ts +5 -0
- package/dist/processors/implementations/storytelling-trigger-processor.js +69 -16
- package/dist/processors/implementations/test-auto-creation-processor.js +39 -36
- package/dist/reporting/framework-reporting-system.d.ts +3 -0
- package/dist/reporting/framework-reporting-system.js +61 -8
- package/dist/reporting/log-parser.js +188 -105
- package/dist/reporting/metrics.js +42 -18
- package/dist/security/prompt-security-validator.js +8 -7
- package/dist/security/security-auditor.d.ts +4 -0
- package/dist/security/security-auditor.js +132 -57
- package/dist/security/security-hardener.d.ts +2 -0
- package/dist/security/security-hardener.js +31 -6
- package/dist/security/security-headers.d.ts +2 -0
- package/dist/security/security-headers.js +23 -21
- package/dist/security/security-scanner.js +18 -4
- package/dist/session/session-cleanup-manager.d.ts +2 -0
- package/dist/session/session-cleanup-manager.js +29 -8
- package/dist/session/session-monitor.d.ts +14 -4
- package/dist/session/session-monitor.js +208 -106
- package/dist/session/session-state-manager.d.ts +11 -0
- package/dist/session/session-state-manager.js +90 -8
- package/docs-site/docs/plates/activity-log.md +38 -0
- package/docs-site/docs/plates/cursor-compact.md +35 -0
- package/docs-site/docs/plates/grok-compact.md +35 -0
- package/docs-site/docs/plates/index.md +25 -3
- package/docs-site/docs/plates/inference-files.md +35 -0
- package/docs-site/docs/plates/kept-line.md +35 -0
- package/docs-site/docs/plates/lens-gate.md +35 -0
- package/docs-site/docs/plates/lens-page.md +35 -0
- package/docs-site/docs/plates/notes-page.md +35 -0
- package/docs-site/docs/plates/package-face.md +35 -0
- package/docs-site/docs/plates/payload-heat.md +35 -0
- package/docs-site/docs/plates/pickup-stamp.md +35 -0
- package/docs-site/docs/plates/pre-tool.md +35 -0
- package/docs-site/docs/plates/record-map.md +41 -0
- package/docs-site/docs/plates/reflection-page.md +35 -0
- package/docs-site/docs/plates/review.md +57 -0
- package/docs-site/docs/plates/session-capture.md +38 -0
- package/docs-site/docs/plates/site-manual.md +35 -0
- package/docs-site/docs/plates/stamp-plate.md +35 -0
- package/docs-site/docs/plates/station-card.md +35 -0
- package/docs-site/docs/plates/station-heat.md +35 -0
- package/docs-site/docs/plates/suit-organs.md +38 -0
- package/docs-site/docs/plates/suit-settings.md +35 -0
- package/docs-site/docs/plates/suit-wear.md +37 -0
- package/docs-site/docs/plates/trail-state.md +35 -0
- package/docs-site/docs/plates/work-fresh.md +35 -0
- package/docs-site/docs/plates/write-home.md +38 -0
- package/package.json +3 -2
- package/scripts/node/install-bridges.cjs +302 -78
- package/scripts/node/postinstall.cjs +14 -3
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/architect-tools.server.ts +25 -20
- package/src/mcps/orchestrator/server.ts +33 -19
- package/xray/features.json +1 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.js.map +0 -1
|
@@ -30,11 +30,15 @@ export interface SecurityAuditResult {
|
|
|
30
30
|
export declare class SecurityAuditor {
|
|
31
31
|
private readonly dangerousPatterns;
|
|
32
32
|
private readonly dangerousImports;
|
|
33
|
+
private readonly compiledImports;
|
|
34
|
+
private textCache;
|
|
33
35
|
/**
|
|
34
36
|
* Run comprehensive security audit
|
|
35
37
|
*/
|
|
36
38
|
auditProject(projectPath?: string): Promise<SecurityAuditResult>;
|
|
37
39
|
private getAllFiles;
|
|
40
|
+
private visitNamed;
|
|
41
|
+
private readText;
|
|
38
42
|
private shouldSkipDirectory;
|
|
39
43
|
private shouldAuditFile;
|
|
40
44
|
private auditFile;
|
|
@@ -9,6 +9,20 @@
|
|
|
9
9
|
import { readFileSync, readdirSync, statSync } from "fs";
|
|
10
10
|
import { join } from "path";
|
|
11
11
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
12
|
+
const RECOMMENDATIONS = {
|
|
13
|
+
"code-injection": "Use static code analysis and avoid dynamic code execution",
|
|
14
|
+
"command-injection": "Validate and sanitize all user inputs, use parameterized commands",
|
|
15
|
+
"sql-injection": "Use parameterized queries or ORM with built-in protection",
|
|
16
|
+
"path-traversal": "Validate paths, use allowlists, resolve to absolute paths",
|
|
17
|
+
"hardcoded-secrets": "Use environment variables or secure credential management",
|
|
18
|
+
"weak-cryptography": "Use cryptographically secure random number generators",
|
|
19
|
+
"information-disclosure": "Avoid logging sensitive information, use proper log levels",
|
|
20
|
+
"input-validation": "Implement comprehensive input validation and sanitization",
|
|
21
|
+
deserialization: "Validate serialized data, use safe deserialization libraries",
|
|
22
|
+
"race-conditions": "Use proper synchronization primitives",
|
|
23
|
+
"dangerous-imports": "Review usage and implement proper access controls",
|
|
24
|
+
"file-permissions": "Restrict file permissions to minimum required access",
|
|
25
|
+
};
|
|
12
26
|
export class SecurityAuditor {
|
|
13
27
|
dangerousPatterns = [
|
|
14
28
|
// Code injection
|
|
@@ -17,18 +31,21 @@ export class SecurityAuditor {
|
|
|
17
31
|
severity: "critical",
|
|
18
32
|
category: "code-injection",
|
|
19
33
|
cwe: "CWE-95",
|
|
34
|
+
hints: ["eval"],
|
|
20
35
|
},
|
|
21
36
|
{
|
|
22
37
|
pattern: /Function\s*\(/g,
|
|
23
38
|
severity: "critical",
|
|
24
39
|
category: "code-injection",
|
|
25
40
|
cwe: "CWE-95",
|
|
41
|
+
hints: ["Function"],
|
|
26
42
|
},
|
|
27
43
|
{
|
|
28
44
|
pattern: /new\s+Function\s*\(/g,
|
|
29
45
|
severity: "critical",
|
|
30
46
|
category: "code-injection",
|
|
31
47
|
cwe: "CWE-95",
|
|
48
|
+
hints: ["Function"],
|
|
32
49
|
},
|
|
33
50
|
// Command injection
|
|
34
51
|
{
|
|
@@ -36,18 +53,21 @@ export class SecurityAuditor {
|
|
|
36
53
|
severity: "high",
|
|
37
54
|
category: "command-injection",
|
|
38
55
|
cwe: "CWE-78",
|
|
56
|
+
hints: ["child_process"],
|
|
39
57
|
},
|
|
40
58
|
{
|
|
41
59
|
pattern: /child_process\.spawn\s*\(/g,
|
|
42
60
|
severity: "high",
|
|
43
61
|
category: "command-injection",
|
|
44
62
|
cwe: "CWE-78",
|
|
63
|
+
hints: ["child_process"],
|
|
45
64
|
},
|
|
46
65
|
{
|
|
47
66
|
pattern: /execSync\s*\(/g,
|
|
48
67
|
severity: "high",
|
|
49
68
|
category: "command-injection",
|
|
50
69
|
cwe: "CWE-78",
|
|
70
|
+
hints: ["execSync"],
|
|
51
71
|
},
|
|
52
72
|
// SQL injection (if applicable)
|
|
53
73
|
{
|
|
@@ -55,12 +75,14 @@ export class SecurityAuditor {
|
|
|
55
75
|
severity: "high",
|
|
56
76
|
category: "sql-injection",
|
|
57
77
|
cwe: "CWE-89",
|
|
78
|
+
hints: ["SELECT", "+"],
|
|
58
79
|
},
|
|
59
80
|
{
|
|
60
81
|
pattern: /INSERT.*\+/g,
|
|
61
82
|
severity: "high",
|
|
62
83
|
category: "sql-injection",
|
|
63
84
|
cwe: "CWE-89",
|
|
85
|
+
hints: ["INSERT", "+"],
|
|
64
86
|
},
|
|
65
87
|
// Path traversal
|
|
66
88
|
{
|
|
@@ -68,12 +90,14 @@ export class SecurityAuditor {
|
|
|
68
90
|
severity: "high",
|
|
69
91
|
category: "path-traversal",
|
|
70
92
|
cwe: "CWE-22",
|
|
93
|
+
hints: [".."],
|
|
71
94
|
},
|
|
72
95
|
{
|
|
73
96
|
pattern: /path\.join\s*\(\s*\.\./g,
|
|
74
97
|
severity: "high",
|
|
75
98
|
category: "path-traversal",
|
|
76
99
|
cwe: "CWE-22",
|
|
100
|
+
hints: ["path.join", ".."],
|
|
77
101
|
},
|
|
78
102
|
// Hardcoded secrets
|
|
79
103
|
{
|
|
@@ -81,18 +105,21 @@ export class SecurityAuditor {
|
|
|
81
105
|
severity: "high",
|
|
82
106
|
category: "hardcoded-secrets",
|
|
83
107
|
cwe: "CWE-798",
|
|
108
|
+
hints: ["password"],
|
|
84
109
|
},
|
|
85
110
|
{
|
|
86
111
|
pattern: /api[_-]?key\s*[:=]\s*['"][^'"]*['"]/gi,
|
|
87
112
|
severity: "high",
|
|
88
113
|
category: "hardcoded-secrets",
|
|
89
114
|
cwe: "CWE-798",
|
|
115
|
+
hints: ["api"],
|
|
90
116
|
},
|
|
91
117
|
{
|
|
92
118
|
pattern: /secret\s*[:=]\s*['"][^'"]*['"]/gi,
|
|
93
119
|
severity: "high",
|
|
94
120
|
category: "hardcoded-secrets",
|
|
95
121
|
cwe: "CWE-798",
|
|
122
|
+
hints: ["secret"],
|
|
96
123
|
},
|
|
97
124
|
// Insecure random
|
|
98
125
|
{
|
|
@@ -100,6 +127,7 @@ export class SecurityAuditor {
|
|
|
100
127
|
severity: "medium",
|
|
101
128
|
category: "weak-cryptography",
|
|
102
129
|
cwe: "CWE-338",
|
|
130
|
+
hints: ["Math.random"],
|
|
103
131
|
},
|
|
104
132
|
// Console logging sensitive data
|
|
105
133
|
{
|
|
@@ -107,12 +135,14 @@ export class SecurityAuditor {
|
|
|
107
135
|
severity: "medium",
|
|
108
136
|
category: "information-disclosure",
|
|
109
137
|
cwe: "CWE-532",
|
|
138
|
+
hints: ["console" + ".log", "password"],
|
|
110
139
|
},
|
|
111
140
|
{
|
|
112
141
|
pattern: /console\.log\s*\([^)]*secret[^)]*\)/gi,
|
|
113
142
|
severity: "medium",
|
|
114
143
|
category: "information-disclosure",
|
|
115
144
|
cwe: "CWE-532",
|
|
145
|
+
hints: ["console" + ".log", "secret"],
|
|
116
146
|
},
|
|
117
147
|
// Missing input validation
|
|
118
148
|
{
|
|
@@ -120,12 +150,14 @@ export class SecurityAuditor {
|
|
|
120
150
|
severity: "medium",
|
|
121
151
|
category: "input-validation",
|
|
122
152
|
cwe: "CWE-20",
|
|
153
|
+
hints: ["req.body"],
|
|
123
154
|
},
|
|
124
155
|
{
|
|
125
156
|
pattern: /req\.query\./g,
|
|
126
157
|
severity: "medium",
|
|
127
158
|
category: "input-validation",
|
|
128
159
|
cwe: "CWE-20",
|
|
160
|
+
hints: ["req.query"],
|
|
129
161
|
},
|
|
130
162
|
// Insecure deserialization
|
|
131
163
|
{
|
|
@@ -133,6 +165,7 @@ export class SecurityAuditor {
|
|
|
133
165
|
severity: "medium",
|
|
134
166
|
category: "deserialization",
|
|
135
167
|
cwe: "CWE-502",
|
|
168
|
+
hints: ["JSON.parse"],
|
|
136
169
|
},
|
|
137
170
|
// Race conditions
|
|
138
171
|
{
|
|
@@ -140,6 +173,7 @@ export class SecurityAuditor {
|
|
|
140
173
|
severity: "low",
|
|
141
174
|
category: "race-conditions",
|
|
142
175
|
cwe: "CWE-362",
|
|
176
|
+
hints: ["setTimeout", "0"],
|
|
143
177
|
},
|
|
144
178
|
// Information disclosure in errors
|
|
145
179
|
{
|
|
@@ -147,6 +181,7 @@ export class SecurityAuditor {
|
|
|
147
181
|
severity: "low",
|
|
148
182
|
category: "information-disclosure",
|
|
149
183
|
cwe: "CWE-209",
|
|
184
|
+
hints: ["throw", "error", "stack"],
|
|
150
185
|
},
|
|
151
186
|
];
|
|
152
187
|
dangerousImports = [
|
|
@@ -161,55 +196,97 @@ export class SecurityAuditor {
|
|
|
161
196
|
"worker_threads",
|
|
162
197
|
"vm",
|
|
163
198
|
];
|
|
199
|
+
compiledImports = this.dangerousImports.map((name) => ({
|
|
200
|
+
name,
|
|
201
|
+
patterns: [
|
|
202
|
+
new RegExp(`import.*from.*['"]${name}['"]`),
|
|
203
|
+
new RegExp(`require\\s*\\(\\s*['"]${name}['"]\\s*\\)`),
|
|
204
|
+
new RegExp(`import.*${name}`),
|
|
205
|
+
],
|
|
206
|
+
}));
|
|
207
|
+
textCache;
|
|
164
208
|
/**
|
|
165
209
|
* Run comprehensive security audit
|
|
166
210
|
*/
|
|
167
211
|
async auditProject(projectPath = ".") {
|
|
168
212
|
const jobId = `security-audit-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
169
213
|
const issues = [];
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
214
|
+
this.textCache = new Map();
|
|
215
|
+
try {
|
|
216
|
+
const files = this.getAllFiles(projectPath);
|
|
217
|
+
frameworkLogger.log("security-auditor", "scan-start", "info", {
|
|
218
|
+
jobId,
|
|
219
|
+
filesCount: files.length,
|
|
220
|
+
projectPath,
|
|
221
|
+
});
|
|
222
|
+
for (const file of files) {
|
|
223
|
+
if (this.shouldAuditFile(file)) {
|
|
224
|
+
const fileIssues = await this.auditFile(file);
|
|
225
|
+
issues.push(...fileIssues);
|
|
226
|
+
}
|
|
180
227
|
}
|
|
228
|
+
// Additional checks
|
|
229
|
+
issues.push(...this.auditPackageJson(projectPath));
|
|
230
|
+
issues.push(...this.auditConfiguration(projectPath));
|
|
231
|
+
issues.push(...this.auditDependencies(projectPath));
|
|
232
|
+
const summary = this.generateSummary(issues);
|
|
233
|
+
const score = this.calculateSecurityScore(issues, files.length);
|
|
234
|
+
return {
|
|
235
|
+
totalFiles: files.length,
|
|
236
|
+
issues,
|
|
237
|
+
summary,
|
|
238
|
+
score,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
this.textCache = undefined;
|
|
181
243
|
}
|
|
182
|
-
// Additional checks
|
|
183
|
-
issues.push(...this.auditPackageJson(projectPath));
|
|
184
|
-
issues.push(...this.auditConfiguration(projectPath));
|
|
185
|
-
issues.push(...this.auditDependencies(projectPath));
|
|
186
|
-
const summary = this.generateSummary(issues);
|
|
187
|
-
const score = this.calculateSecurityScore(issues, files.length);
|
|
188
|
-
return {
|
|
189
|
-
totalFiles: files.length,
|
|
190
|
-
issues,
|
|
191
|
-
summary,
|
|
192
|
-
score,
|
|
193
|
-
};
|
|
194
244
|
}
|
|
195
245
|
getAllFiles(dirPath) {
|
|
196
246
|
const files = [];
|
|
197
247
|
const traverse = (currentPath) => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
// Dirent already knows file vs directory. Stat names and symlinks so the target type matches statSync.
|
|
249
|
+
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
250
|
+
for (const entry of entries) {
|
|
251
|
+
if (typeof entry === "string") {
|
|
252
|
+
this.visitNamed(currentPath, entry, files, traverse);
|
|
253
|
+
continue;
|
|
204
254
|
}
|
|
205
|
-
|
|
206
|
-
|
|
255
|
+
const fullPath = join(currentPath, entry.name);
|
|
256
|
+
if (typeof entry.isSymbolicLink === "function" && entry.isSymbolicLink()) {
|
|
257
|
+
this.visitNamed(currentPath, entry.name, files, traverse);
|
|
258
|
+
continue;
|
|
207
259
|
}
|
|
260
|
+
if (entry.isDirectory()) {
|
|
261
|
+
if (!this.shouldSkipDirectory(entry.name))
|
|
262
|
+
traverse(fullPath);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (entry.isFile())
|
|
266
|
+
files.push(fullPath);
|
|
208
267
|
}
|
|
209
268
|
};
|
|
210
269
|
traverse(dirPath);
|
|
211
270
|
return files;
|
|
212
271
|
}
|
|
272
|
+
visitNamed(currentPath, name, files, traverse) {
|
|
273
|
+
const fullPath = join(currentPath, name);
|
|
274
|
+
const stat = statSync(fullPath);
|
|
275
|
+
if (stat.isDirectory() && !this.shouldSkipDirectory(name)) {
|
|
276
|
+
traverse(fullPath);
|
|
277
|
+
}
|
|
278
|
+
else if (stat.isFile()) {
|
|
279
|
+
files.push(fullPath);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
readText(filePath) {
|
|
283
|
+
const cached = this.textCache?.get(filePath);
|
|
284
|
+
if (cached !== undefined)
|
|
285
|
+
return cached;
|
|
286
|
+
const text = readFileSync(filePath, "utf-8");
|
|
287
|
+
this.textCache?.set(filePath, text);
|
|
288
|
+
return text;
|
|
289
|
+
}
|
|
213
290
|
shouldSkipDirectory(dirName) {
|
|
214
291
|
const skipDirs = [
|
|
215
292
|
"node_modules",
|
|
@@ -234,14 +311,30 @@ export class SecurityAuditor {
|
|
|
234
311
|
async auditFile(filePath) {
|
|
235
312
|
const issues = [];
|
|
236
313
|
try {
|
|
237
|
-
const content =
|
|
314
|
+
const content = this.readText(filePath);
|
|
238
315
|
const lines = content.split("\n");
|
|
239
316
|
// Pattern-based security checks
|
|
240
317
|
for (let i = 0; i < lines.length; i++) {
|
|
241
318
|
const line = lines[i];
|
|
242
319
|
const lineNumber = i + 1;
|
|
243
|
-
|
|
320
|
+
let folded;
|
|
321
|
+
for (const { pattern, severity, category, cwe, hints } of this
|
|
244
322
|
.dangerousPatterns) {
|
|
323
|
+
// lastIndex carries across lines. Skip only when the search would start at 0 and a hint is absent.
|
|
324
|
+
if (line && pattern.lastIndex === 0) {
|
|
325
|
+
const hay = pattern.flags.includes("i")
|
|
326
|
+
? (folded ??= line.toLowerCase())
|
|
327
|
+
: line;
|
|
328
|
+
let miss = false;
|
|
329
|
+
for (const hint of hints) {
|
|
330
|
+
if (!hay.includes(hint)) {
|
|
331
|
+
miss = true;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (miss)
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
245
338
|
const matches = line?.match(pattern);
|
|
246
339
|
if (matches && line) {
|
|
247
340
|
// Skip false positives in security validation and test code
|
|
@@ -304,19 +397,15 @@ export class SecurityAuditor {
|
|
|
304
397
|
}
|
|
305
398
|
auditImports(content, filePath) {
|
|
306
399
|
const issues = [];
|
|
307
|
-
for (const
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
new RegExp(`require\\s*\\(\\s*['"]${dangerousImport}['"]\\s*\\)`, "g"),
|
|
311
|
-
new RegExp(`import.*${dangerousImport}`, "g"),
|
|
312
|
-
];
|
|
313
|
-
for (const pattern of importPatterns) {
|
|
400
|
+
for (const { name, patterns } of this.compiledImports) {
|
|
401
|
+
for (const pattern of patterns) {
|
|
402
|
+
pattern.lastIndex = 0;
|
|
314
403
|
if (pattern.test(content)) {
|
|
315
404
|
issues.push({
|
|
316
405
|
severity: "medium",
|
|
317
406
|
category: "dangerous-imports",
|
|
318
407
|
file: filePath,
|
|
319
|
-
description: `Potentially dangerous import detected: ${
|
|
408
|
+
description: `Potentially dangerous import detected: ${name}`,
|
|
320
409
|
recommendation: "Review usage and ensure proper sandboxing/validation",
|
|
321
410
|
cwe: "CWE-350",
|
|
322
411
|
});
|
|
@@ -363,7 +452,7 @@ export class SecurityAuditor {
|
|
|
363
452
|
const issues = [];
|
|
364
453
|
try {
|
|
365
454
|
const packagePath = join(projectPath, "package.json");
|
|
366
|
-
const packageJson = JSON.parse(
|
|
455
|
+
const packageJson = JSON.parse(this.readText(packagePath));
|
|
367
456
|
// Check for vulnerable dependencies
|
|
368
457
|
const allDeps = {
|
|
369
458
|
...packageJson.dependencies,
|
|
@@ -411,7 +500,7 @@ export class SecurityAuditor {
|
|
|
411
500
|
for (const configFile of configFiles) {
|
|
412
501
|
const configPath = join(projectPath, configFile);
|
|
413
502
|
try {
|
|
414
|
-
const content =
|
|
503
|
+
const content = this.readText(configPath);
|
|
415
504
|
// Check for hardcoded secrets
|
|
416
505
|
const secretPatterns = [
|
|
417
506
|
/password\s*[:=]\s*['"][^'"]*['"]/gi,
|
|
@@ -462,21 +551,7 @@ export class SecurityAuditor {
|
|
|
462
551
|
return issues;
|
|
463
552
|
}
|
|
464
553
|
getRecommendationForCategory(category) {
|
|
465
|
-
|
|
466
|
-
"code-injection": "Use static code analysis and avoid dynamic code execution",
|
|
467
|
-
"command-injection": "Validate and sanitize all user inputs, use parameterized commands",
|
|
468
|
-
"sql-injection": "Use parameterized queries or ORM with built-in protection",
|
|
469
|
-
"path-traversal": "Validate paths, use allowlists, resolve to absolute paths",
|
|
470
|
-
"hardcoded-secrets": "Use environment variables or secure credential management",
|
|
471
|
-
"weak-cryptography": "Use cryptographically secure random number generators",
|
|
472
|
-
"information-disclosure": "Avoid logging sensitive information, use proper log levels",
|
|
473
|
-
"input-validation": "Implement comprehensive input validation and sanitization",
|
|
474
|
-
deserialization: "Validate serialized data, use safe deserialization libraries",
|
|
475
|
-
"race-conditions": "Use proper synchronization primitives",
|
|
476
|
-
"dangerous-imports": "Review usage and implement proper access controls",
|
|
477
|
-
"file-permissions": "Restrict file permissions to minimum required access",
|
|
478
|
-
};
|
|
479
|
-
return (recommendations[category] ||
|
|
554
|
+
return (RECOMMENDATIONS[category] ||
|
|
480
555
|
"Review and implement appropriate security measures");
|
|
481
556
|
}
|
|
482
557
|
generateSummary(issues) {
|
|
@@ -18,6 +18,7 @@ export interface SecurityHardeningConfig {
|
|
|
18
18
|
}
|
|
19
19
|
export declare class SecurityHardener {
|
|
20
20
|
private config;
|
|
21
|
+
private readonly patternCache;
|
|
21
22
|
constructor(config?: Partial<SecurityHardeningConfig>);
|
|
22
23
|
/**
|
|
23
24
|
* Apply security hardening based on audit results
|
|
@@ -44,6 +45,7 @@ export declare class SecurityHardener {
|
|
|
44
45
|
valid: boolean;
|
|
45
46
|
errors: string[];
|
|
46
47
|
};
|
|
48
|
+
private regexFor;
|
|
47
49
|
/**
|
|
48
50
|
* Check rate limiting
|
|
49
51
|
*/
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { promises as fs } from "fs";
|
|
10
10
|
export class SecurityHardener {
|
|
11
11
|
config;
|
|
12
|
+
patternCache = new Map();
|
|
12
13
|
constructor(config = {}) {
|
|
13
14
|
this.config = {
|
|
14
15
|
enableInputValidation: true,
|
|
@@ -127,7 +128,7 @@ export class SecurityHardener {
|
|
|
127
128
|
}
|
|
128
129
|
if (schema.pattern &&
|
|
129
130
|
typeof input === "string" &&
|
|
130
|
-
!
|
|
131
|
+
!this.regexFor(String(schema.pattern)).test(input)) {
|
|
131
132
|
errors.push("String does not match required pattern");
|
|
132
133
|
}
|
|
133
134
|
return {
|
|
@@ -135,6 +136,16 @@ export class SecurityHardener {
|
|
|
135
136
|
errors,
|
|
136
137
|
};
|
|
137
138
|
}
|
|
139
|
+
regexFor(source) {
|
|
140
|
+
const cached = this.patternCache.get(source);
|
|
141
|
+
if (cached) {
|
|
142
|
+
cached.lastIndex = 0;
|
|
143
|
+
return cached;
|
|
144
|
+
}
|
|
145
|
+
const compiled = new RegExp(source);
|
|
146
|
+
this.patternCache.set(source, compiled);
|
|
147
|
+
return compiled;
|
|
148
|
+
}
|
|
138
149
|
/**
|
|
139
150
|
* Check rate limiting
|
|
140
151
|
*/
|
|
@@ -143,13 +154,27 @@ export class SecurityHardener {
|
|
|
143
154
|
return true;
|
|
144
155
|
const now = Date.now();
|
|
145
156
|
const windowStart = now - this.config.rateLimitWindowMs;
|
|
146
|
-
const userRequests = requests.get(identifier)
|
|
147
|
-
|
|
148
|
-
|
|
157
|
+
const userRequests = requests.get(identifier);
|
|
158
|
+
if (!userRequests) {
|
|
159
|
+
requests.set(identifier, [now]);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
let recent = 0;
|
|
163
|
+
for (let i = 0; i < userRequests.length; i++) {
|
|
164
|
+
const time = userRequests[i];
|
|
165
|
+
if (time !== undefined && time > windowStart)
|
|
166
|
+
recent++;
|
|
167
|
+
}
|
|
168
|
+
if (recent >= this.config.rateLimitMaxRequests)
|
|
149
169
|
return false;
|
|
170
|
+
let write = 0;
|
|
171
|
+
for (let i = 0; i < userRequests.length; i++) {
|
|
172
|
+
const time = userRequests[i];
|
|
173
|
+
if (time !== undefined && time > windowStart)
|
|
174
|
+
userRequests[write++] = time;
|
|
150
175
|
}
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
userRequests.length = write;
|
|
177
|
+
userRequests.push(now);
|
|
153
178
|
return true;
|
|
154
179
|
}
|
|
155
180
|
/**
|
|
@@ -34,11 +34,13 @@ export interface SecurityHeadersConfig {
|
|
|
34
34
|
}
|
|
35
35
|
export declare class SecurityHeadersMiddleware {
|
|
36
36
|
private config;
|
|
37
|
+
private headerPairs;
|
|
37
38
|
constructor(config?: Partial<SecurityHeadersConfig>);
|
|
38
39
|
/**
|
|
39
40
|
* Apply security headers to HTTP response
|
|
40
41
|
*/
|
|
41
42
|
applySecurityHeaders(response: HttpResponse): void;
|
|
43
|
+
private rebuildHeaders;
|
|
42
44
|
/**
|
|
43
45
|
* Express.js middleware function
|
|
44
46
|
*/
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
10
10
|
export class SecurityHeadersMiddleware {
|
|
11
11
|
config;
|
|
12
|
+
headerPairs = [];
|
|
12
13
|
constructor(config = {}) {
|
|
13
14
|
this.config = {
|
|
14
15
|
enableCSP: true,
|
|
@@ -23,6 +24,7 @@ export class SecurityHeadersMiddleware {
|
|
|
23
24
|
hstsPreload: false,
|
|
24
25
|
...config,
|
|
25
26
|
};
|
|
27
|
+
this.rebuildHeaders();
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Apply security headers to HTTP response
|
|
@@ -32,14 +34,19 @@ export class SecurityHeadersMiddleware {
|
|
|
32
34
|
frameworkLogger.log("security-headers", "invalid-response-object", "warning", { warning: "SecurityHeadersMiddleware: Invalid response object" });
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
+
for (const [key, value] of this.headerPairs) {
|
|
38
|
+
response.setHeader(key, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
rebuildHeaders() {
|
|
42
|
+
const headers = [];
|
|
37
43
|
if (this.config.enableCSP) {
|
|
38
|
-
headers[
|
|
44
|
+
headers.push([
|
|
45
|
+
"Content-Security-Policy",
|
|
39
46
|
this.config.customCSP ||
|
|
40
|
-
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'"
|
|
47
|
+
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'",
|
|
48
|
+
]);
|
|
41
49
|
}
|
|
42
|
-
// HTTP Strict Transport Security
|
|
43
50
|
if (this.config.enableHSTS) {
|
|
44
51
|
let hstsValue = `max-age=${this.config.hstsMaxAge}`;
|
|
45
52
|
if (this.config.hstsIncludeSubdomains) {
|
|
@@ -48,33 +55,27 @@ export class SecurityHeadersMiddleware {
|
|
|
48
55
|
if (this.config.hstsPreload) {
|
|
49
56
|
hstsValue += "; preload";
|
|
50
57
|
}
|
|
51
|
-
headers["Strict-Transport-Security"
|
|
58
|
+
headers.push(["Strict-Transport-Security", hstsValue]);
|
|
52
59
|
}
|
|
53
|
-
// X-Frame-Options
|
|
54
60
|
if (this.config.enableFrameOptions) {
|
|
55
|
-
headers["X-Frame-Options"
|
|
61
|
+
headers.push(["X-Frame-Options", "DENY"]);
|
|
56
62
|
}
|
|
57
|
-
// X-XSS-Protection
|
|
58
63
|
if (this.config.enableXSSProtection) {
|
|
59
|
-
headers["X-XSS-Protection"
|
|
64
|
+
headers.push(["X-XSS-Protection", "1; mode=block"]);
|
|
60
65
|
}
|
|
61
|
-
// X-Content-Type-Options
|
|
62
66
|
if (this.config.enableContentTypeOptions) {
|
|
63
|
-
headers["X-Content-Type-Options"
|
|
67
|
+
headers.push(["X-Content-Type-Options", "nosniff"]);
|
|
64
68
|
}
|
|
65
|
-
// Referrer-Policy
|
|
66
69
|
if (this.config.enableReferrerPolicy) {
|
|
67
|
-
headers["Referrer-Policy"
|
|
70
|
+
headers.push(["Referrer-Policy", "strict-origin-when-cross-origin"]);
|
|
68
71
|
}
|
|
69
|
-
// Permissions-Policy
|
|
70
72
|
if (this.config.enablePermissionsPolicy) {
|
|
71
|
-
headers[
|
|
72
|
-
"
|
|
73
|
+
headers.push([
|
|
74
|
+
"Permissions-Policy",
|
|
75
|
+
"geolocation=(), microphone=(), camera=()",
|
|
76
|
+
]);
|
|
73
77
|
}
|
|
74
|
-
|
|
75
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
76
|
-
response.setHeader(key, value);
|
|
77
|
-
});
|
|
78
|
+
this.headerPairs = headers;
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
80
81
|
* Express.js middleware function
|
|
@@ -105,6 +106,7 @@ export class SecurityHeadersMiddleware {
|
|
|
105
106
|
*/
|
|
106
107
|
updateConfig(newConfig) {
|
|
107
108
|
this.config = { ...this.config, ...newConfig };
|
|
109
|
+
this.rebuildHeaders();
|
|
108
110
|
}
|
|
109
111
|
/**
|
|
110
112
|
* Get current configuration
|
|
@@ -243,16 +243,30 @@ export class SecurityScanner {
|
|
|
243
243
|
*/
|
|
244
244
|
generateRecommendations(vulnerabilities) {
|
|
245
245
|
const recommendations = [];
|
|
246
|
-
|
|
246
|
+
let critical = false;
|
|
247
|
+
let high = false;
|
|
248
|
+
let packaged = false;
|
|
249
|
+
let eslint = false;
|
|
250
|
+
for (const vuln of vulnerabilities) {
|
|
251
|
+
if (vuln.severity === "critical")
|
|
252
|
+
critical = true;
|
|
253
|
+
else if (vuln.severity === "high")
|
|
254
|
+
high = true;
|
|
255
|
+
if (vuln.package)
|
|
256
|
+
packaged = true;
|
|
257
|
+
if (vuln.id.includes("eslint"))
|
|
258
|
+
eslint = true;
|
|
259
|
+
}
|
|
260
|
+
if (critical) {
|
|
247
261
|
recommendations.push("🚨 Critical security vulnerabilities found - immediate action required");
|
|
248
262
|
}
|
|
249
|
-
if (
|
|
263
|
+
if (high) {
|
|
250
264
|
recommendations.push("⚠️ High-severity vulnerabilities detected - prioritize fixes");
|
|
251
265
|
}
|
|
252
|
-
if (
|
|
266
|
+
if (packaged) {
|
|
253
267
|
recommendations.push("📦 Update vulnerable dependencies to latest secure versions");
|
|
254
268
|
}
|
|
255
|
-
if (
|
|
269
|
+
if (eslint) {
|
|
256
270
|
recommendations.push("🔧 Fix code security issues identified by ESLint");
|
|
257
271
|
}
|
|
258
272
|
recommendations.push("🔍 Run regular security scans and keep dependencies updated");
|
|
@@ -37,6 +37,8 @@ export declare class SessionCleanupManager {
|
|
|
37
37
|
private cleanupInterval?;
|
|
38
38
|
private _sessionMetadata?;
|
|
39
39
|
private _metadataLoaded;
|
|
40
|
+
/** Same object the store holds, so a one-field write does not clone every session. */
|
|
41
|
+
private metadataRecord;
|
|
40
42
|
private sessionMonitor;
|
|
41
43
|
constructor(stateManager: XrayStateManager, config?: Partial<CleanupConfig>, sessionMonitor?: SessionMonitor);
|
|
42
44
|
/**
|