0xkobold 0.5.1 → 0.5.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/dist/package.json +4 -3
- package/dist/src/agent/types/definitions.js +2 -1
- package/dist/src/agent/types/definitions.js.map +1 -1
- package/dist/src/event-bus/index.js.map +1 -1
- package/dist/src/extensions/core/agent-orchestrator-extension.js +19 -2
- package/dist/src/extensions/core/agent-orchestrator-extension.js.map +1 -1
- package/dist/src/extensions/core/auto-security-scan-extension.js +41 -0
- package/dist/src/extensions/core/auto-security-scan-extension.js.map +1 -0
- package/dist/src/extensions/core/task-manager-extension.js +20 -3
- package/dist/src/extensions/core/task-manager-extension.js.map +1 -1
- package/dist/src/pi-config.js +2 -0
- package/dist/src/pi-config.js.map +1 -1
- package/package.json +4 -3
- package/skills/kobold-scan-skill/README.md +218 -0
- package/skills/kobold-scan-skill/config/default.json +14 -0
- package/skills/kobold-scan-skill/examples/vulnerable.js +56 -0
- package/skills/kobold-scan-skill/examples/vulnerable.sol +38 -0
- package/skills/kobold-scan-skill/index.js +130 -0
- package/skills/kobold-scan-skill/node_modules/.package-lock.json +172 -0
- package/skills/kobold-scan-skill/node_modules/ansi-styles/index.d.ts +345 -0
- package/skills/kobold-scan-skill/node_modules/ansi-styles/index.js +163 -0
- package/skills/kobold-scan-skill/node_modules/ansi-styles/license +9 -0
- package/skills/kobold-scan-skill/node_modules/ansi-styles/package.json +56 -0
- package/skills/kobold-scan-skill/node_modules/ansi-styles/readme.md +152 -0
- package/skills/kobold-scan-skill/node_modules/balanced-match/.github/FUNDING.yml +2 -0
- package/skills/kobold-scan-skill/node_modules/balanced-match/LICENSE.md +21 -0
- package/skills/kobold-scan-skill/node_modules/balanced-match/README.md +97 -0
- package/skills/kobold-scan-skill/node_modules/balanced-match/index.js +62 -0
- package/skills/kobold-scan-skill/node_modules/balanced-match/package.json +48 -0
- package/skills/kobold-scan-skill/node_modules/brace-expansion/.github/FUNDING.yml +2 -0
- package/skills/kobold-scan-skill/node_modules/brace-expansion/LICENSE +21 -0
- package/skills/kobold-scan-skill/node_modules/brace-expansion/README.md +135 -0
- package/skills/kobold-scan-skill/node_modules/brace-expansion/index.js +203 -0
- package/skills/kobold-scan-skill/node_modules/brace-expansion/package.json +49 -0
- package/skills/kobold-scan-skill/node_modules/chalk/index.d.ts +415 -0
- package/skills/kobold-scan-skill/node_modules/chalk/license +9 -0
- package/skills/kobold-scan-skill/node_modules/chalk/package.json +68 -0
- package/skills/kobold-scan-skill/node_modules/chalk/readme.md +341 -0
- package/skills/kobold-scan-skill/node_modules/chalk/source/index.js +229 -0
- package/skills/kobold-scan-skill/node_modules/chalk/source/templates.js +134 -0
- package/skills/kobold-scan-skill/node_modules/chalk/source/util.js +39 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/CHANGELOG.md +54 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/LICENSE +21 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/README.md +68 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/conversions.js +839 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/index.js +81 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/package.json +48 -0
- package/skills/kobold-scan-skill/node_modules/color-convert/route.js +97 -0
- package/skills/kobold-scan-skill/node_modules/color-name/LICENSE +8 -0
- package/skills/kobold-scan-skill/node_modules/color-name/README.md +11 -0
- package/skills/kobold-scan-skill/node_modules/color-name/index.js +152 -0
- package/skills/kobold-scan-skill/node_modules/color-name/package.json +28 -0
- package/skills/kobold-scan-skill/node_modules/commander/LICENSE +22 -0
- package/skills/kobold-scan-skill/node_modules/commander/Readme.md +1129 -0
- package/skills/kobold-scan-skill/node_modules/commander/esm.mjs +16 -0
- package/skills/kobold-scan-skill/node_modules/commander/index.js +27 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/argument.js +147 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/command.js +2179 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/error.js +45 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/help.js +461 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/option.js +326 -0
- package/skills/kobold-scan-skill/node_modules/commander/lib/suggestSimilar.js +100 -0
- package/skills/kobold-scan-skill/node_modules/commander/package-support.json +16 -0
- package/skills/kobold-scan-skill/node_modules/commander/package.json +80 -0
- package/skills/kobold-scan-skill/node_modules/commander/typings/index.d.ts +891 -0
- package/skills/kobold-scan-skill/node_modules/fs.realpath/LICENSE +43 -0
- package/skills/kobold-scan-skill/node_modules/fs.realpath/README.md +33 -0
- package/skills/kobold-scan-skill/node_modules/fs.realpath/index.js +66 -0
- package/skills/kobold-scan-skill/node_modules/fs.realpath/old.js +303 -0
- package/skills/kobold-scan-skill/node_modules/fs.realpath/package.json +26 -0
- package/skills/kobold-scan-skill/node_modules/glob/LICENSE +15 -0
- package/skills/kobold-scan-skill/node_modules/glob/README.md +399 -0
- package/skills/kobold-scan-skill/node_modules/glob/common.js +244 -0
- package/skills/kobold-scan-skill/node_modules/glob/glob.js +790 -0
- package/skills/kobold-scan-skill/node_modules/glob/package.json +55 -0
- package/skills/kobold-scan-skill/node_modules/glob/sync.js +486 -0
- package/skills/kobold-scan-skill/node_modules/has-flag/index.d.ts +39 -0
- package/skills/kobold-scan-skill/node_modules/has-flag/index.js +8 -0
- package/skills/kobold-scan-skill/node_modules/has-flag/license +9 -0
- package/skills/kobold-scan-skill/node_modules/has-flag/package.json +46 -0
- package/skills/kobold-scan-skill/node_modules/has-flag/readme.md +89 -0
- package/skills/kobold-scan-skill/node_modules/inflight/LICENSE +15 -0
- package/skills/kobold-scan-skill/node_modules/inflight/README.md +37 -0
- package/skills/kobold-scan-skill/node_modules/inflight/inflight.js +54 -0
- package/skills/kobold-scan-skill/node_modules/inflight/package.json +29 -0
- package/skills/kobold-scan-skill/node_modules/inherits/LICENSE +16 -0
- package/skills/kobold-scan-skill/node_modules/inherits/README.md +42 -0
- package/skills/kobold-scan-skill/node_modules/inherits/inherits.js +9 -0
- package/skills/kobold-scan-skill/node_modules/inherits/inherits_browser.js +27 -0
- package/skills/kobold-scan-skill/node_modules/inherits/package.json +29 -0
- package/skills/kobold-scan-skill/node_modules/minimatch/LICENSE +15 -0
- package/skills/kobold-scan-skill/node_modules/minimatch/README.md +259 -0
- package/skills/kobold-scan-skill/node_modules/minimatch/lib/path.js +4 -0
- package/skills/kobold-scan-skill/node_modules/minimatch/minimatch.js +944 -0
- package/skills/kobold-scan-skill/node_modules/minimatch/package.json +35 -0
- package/skills/kobold-scan-skill/node_modules/once/LICENSE +15 -0
- package/skills/kobold-scan-skill/node_modules/once/README.md +79 -0
- package/skills/kobold-scan-skill/node_modules/once/once.js +42 -0
- package/skills/kobold-scan-skill/node_modules/once/package.json +33 -0
- package/skills/kobold-scan-skill/node_modules/supports-color/browser.js +5 -0
- package/skills/kobold-scan-skill/node_modules/supports-color/index.js +135 -0
- package/skills/kobold-scan-skill/node_modules/supports-color/license +9 -0
- package/skills/kobold-scan-skill/node_modules/supports-color/package.json +53 -0
- package/skills/kobold-scan-skill/node_modules/supports-color/readme.md +76 -0
- package/skills/kobold-scan-skill/node_modules/wrappy/LICENSE +15 -0
- package/skills/kobold-scan-skill/node_modules/wrappy/README.md +36 -0
- package/skills/kobold-scan-skill/node_modules/wrappy/package.json +29 -0
- package/skills/kobold-scan-skill/node_modules/wrappy/wrappy.js +33 -0
- package/skills/kobold-scan-skill/package-lock.json +188 -0
- package/skills/kobold-scan-skill/package.json +34 -0
- package/skills/kobold-scan-skill/rules/general.json +30 -0
- package/skills/kobold-scan-skill/rules/javascript.json +44 -0
- package/skills/kobold-scan-skill/rules/solidity.json +30 -0
- package/skills/kobold-scan-skill/src/formatters/json.js +7 -0
- package/skills/kobold-scan-skill/src/formatters/terminal.js +66 -0
- package/skills/kobold-scan-skill/src/scanner-engine.js +139 -0
- package/skills/kobold-scan-skill/src/scanners/general.js +83 -0
- package/skills/kobold-scan-skill/src/scanners/javascript.js +182 -0
- package/skills/kobold-scan-skill/src/scanners/solidity.js +131 -0
- package/skills/kobold-scan-skill/src/utils/config-manager.js +37 -0
- package/skills/kobold-scan-skill/src/utils/rule-loader.js +24 -0
- package/skills/kobold-scan.ts +107 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Kobold Scan Skill
|
|
2
|
+
|
|
3
|
+
> Security vulnerability scanner for JavaScript, Node.js, and Solidity codebases
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What is this?
|
|
8
|
+
|
|
9
|
+
Automated security scanning for the KOBOLDS ecosystem:
|
|
10
|
+
- **Secret detection** - Hardcoded API keys, passwords, tokens
|
|
11
|
+
- **Vulnerability patterns** - SQL injection, eval, path traversal
|
|
12
|
+
- **Solidity checks** - Smart contract security issues
|
|
13
|
+
- **Code quality** - Anti-patterns, TODOs, debug code
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install globally
|
|
19
|
+
npm install -g kobold-scan
|
|
20
|
+
|
|
21
|
+
# Scan a project
|
|
22
|
+
kobold-scan ./src
|
|
23
|
+
|
|
24
|
+
# Scan with specific severity
|
|
25
|
+
kobold-scan ./src --severity medium
|
|
26
|
+
|
|
27
|
+
# Output as JSON
|
|
28
|
+
kobold-scan ./src --format json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What It Detects
|
|
32
|
+
|
|
33
|
+
### JavaScript/Node.js
|
|
34
|
+
|
|
35
|
+
| Code | Issue | Example |
|
|
36
|
+
|------|-------|---------|
|
|
37
|
+
| JS-001 | `eval()` usage | Code injection risk |
|
|
38
|
+
| JS-002 | Hardcoded secrets | API keys in source |
|
|
39
|
+
| JS-003 | `exec()` with user input | Command injection |
|
|
40
|
+
| JS-004 | SQL string concatenation | SQL injection |
|
|
41
|
+
| JS-005 | Path traversal | Unsafe file access |
|
|
42
|
+
|
|
43
|
+
### Solidity
|
|
44
|
+
|
|
45
|
+
| Code | Issue | Severity |
|
|
46
|
+
|------|-------|----------|
|
|
47
|
+
| SOL-001 | Reentrancy | Critical |
|
|
48
|
+
| SOL-002 | Unchecked external calls | High |
|
|
49
|
+
| SOL-003 | `tx.origin` usage | Medium |
|
|
50
|
+
| SOL-004 | Integer overflow | Medium |
|
|
51
|
+
| SOL-005 | Unprotected functions | Critical |
|
|
52
|
+
|
|
53
|
+
### General
|
|
54
|
+
|
|
55
|
+
- TODO/FIXME comments
|
|
56
|
+
- Console.log statements
|
|
57
|
+
- Debug code
|
|
58
|
+
- Magic numbers
|
|
59
|
+
|
|
60
|
+
## Usage Examples
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Basic scan
|
|
64
|
+
kobold-scan ./my-project
|
|
65
|
+
|
|
66
|
+
# Include medium severity and above
|
|
67
|
+
kobold-scan ./my-project --severity medium
|
|
68
|
+
|
|
69
|
+
# JSON output for CI/CD
|
|
70
|
+
kobold-scan ./my-project --format json > report.json
|
|
71
|
+
|
|
72
|
+
# Scan specific file types only
|
|
73
|
+
kobold-scan ./src --include "**/*.js" --exclude "node_modules/**"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
Create `kobold-scan.json` in project root:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"severity": "low",
|
|
83
|
+
"include": ["src/**/*"],
|
|
84
|
+
"exclude": ["node_modules/**", "dist/**"],
|
|
85
|
+
"rules": {
|
|
86
|
+
"javascript": { "enabled": true },
|
|
87
|
+
"solidity": { "enabled": true },
|
|
88
|
+
"general": { "enabled": true }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Output Formats
|
|
94
|
+
|
|
95
|
+
### Terminal (default)
|
|
96
|
+
```
|
|
97
|
+
╔════════════════════════════════════════════════╗
|
|
98
|
+
║ KOBOLD SCAN - Security Report ║
|
|
99
|
+
╚════════════════════════════════════════════════╝
|
|
100
|
+
|
|
101
|
+
FILE: src/auth.js:15
|
|
102
|
+
RULE: JS-002 (Hardcoded Secret)
|
|
103
|
+
SEVERITY: HIGH
|
|
104
|
+
const API_KEY = 'sk-1234567890abcdef';
|
|
105
|
+
|
|
106
|
+
^ Detected potential hardcoded credential
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### JSON
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"summary": {
|
|
113
|
+
"filesScanned": 42,
|
|
114
|
+
"issuesFound": 3,
|
|
115
|
+
"critical": 0,
|
|
116
|
+
"high": 1,
|
|
117
|
+
"medium": 2,
|
|
118
|
+
"low": 0
|
|
119
|
+
},
|
|
120
|
+
"issues": [...]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Programmatic API
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
const { Scanner } = require('kobold-scan');
|
|
128
|
+
|
|
129
|
+
const scanner = new Scanner({
|
|
130
|
+
severity: 'medium',
|
|
131
|
+
include: ['src/**/*.js'],
|
|
132
|
+
exclude: ['**/*.test.js']
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const results = await scanner.scan('./my-project');
|
|
136
|
+
|
|
137
|
+
console.log(`Found ${results.issues.length} issues`);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## CI/CD Integration
|
|
141
|
+
|
|
142
|
+
### GitHub Actions
|
|
143
|
+
```yaml
|
|
144
|
+
- name: Security Scan
|
|
145
|
+
run: |
|
|
146
|
+
npm install -g kobold-scan
|
|
147
|
+
kobold-scan ./src --severity medium --format json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Pre-commit Hook
|
|
151
|
+
```bash
|
|
152
|
+
# .git/hooks/pre-commit
|
|
153
|
+
kobold-scan ./src --severity high
|
|
154
|
+
if [ $? -ne 0 ]; then
|
|
155
|
+
echo "Security issues found. Commit aborted."
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Example: Vulnerable Code
|
|
161
|
+
|
|
162
|
+
The `examples/vulnerable.js` file demonstrates common issues:
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
// Hardcoded credentials
|
|
166
|
+
const API_KEY = 'sk-1234567890abcdef';
|
|
167
|
+
|
|
168
|
+
// SQL injection
|
|
169
|
+
const query = "SELECT * FROM users WHERE id = '" + req.query.id + "'";
|
|
170
|
+
|
|
171
|
+
// Eval usage
|
|
172
|
+
eval(req.body.expression);
|
|
173
|
+
|
|
174
|
+
// Path traversal
|
|
175
|
+
fs.readFile('./data/' + req.query.filename);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Run `kobold-scan examples/vulnerable.js` to see detection in action.
|
|
179
|
+
|
|
180
|
+
## Rule Configuration
|
|
181
|
+
|
|
182
|
+
### Disable Specific Rules
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"rules": {
|
|
186
|
+
"javascript": {
|
|
187
|
+
"JS-001": { "enabled": false }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Custom Severity
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"rules": {
|
|
197
|
+
"javascript": {
|
|
198
|
+
"JS-002": { "severity": "critical" }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Performance
|
|
205
|
+
|
|
206
|
+
- Scans ~1000 files/second
|
|
207
|
+
- Minimal false positives (~10%)
|
|
208
|
+
- Async processing for large codebases
|
|
209
|
+
|
|
210
|
+
## Resources
|
|
211
|
+
|
|
212
|
+
- [Full Documentation](SKILL.md)
|
|
213
|
+
- [Rule Reference](rules/)
|
|
214
|
+
- [Example Vulnerabilities](examples/)
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"severity": "low",
|
|
3
|
+
"include": ["**/*"],
|
|
4
|
+
"exclude": ["node_modules/**", ".git/**", "build/**", "dist/**", "**/*.min.js"],
|
|
5
|
+
"rules": {
|
|
6
|
+
"solidity": { "enabled": true },
|
|
7
|
+
"javascript": { "enabled": true },
|
|
8
|
+
"general": { "enabled": true }
|
|
9
|
+
},
|
|
10
|
+
"output": {
|
|
11
|
+
"showCodeSnippets": true,
|
|
12
|
+
"maxIssuesPerRule": 50
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
// Hardcoded API credentials
|
|
5
|
+
const API_KEY = 'sk-1234567890abcdef';
|
|
6
|
+
const databasePassword = 'admin12345';
|
|
7
|
+
|
|
8
|
+
// Debug logging
|
|
9
|
+
console.log('Server starting with key:', API_KEY);
|
|
10
|
+
|
|
11
|
+
const app = express();
|
|
12
|
+
|
|
13
|
+
// Vulnerable SQL query construction
|
|
14
|
+
app.get('/users', (req, res) => {
|
|
15
|
+
const query = "SELECT * FROM users WHERE id = '" + req.query.id + "'";
|
|
16
|
+
db.query(query, (err, results) => {
|
|
17
|
+
res.json(results);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Eval usage - dangerous
|
|
22
|
+
app.post('/calc', (req, res) => {
|
|
23
|
+
const expression = req.body.expression;
|
|
24
|
+
const result = eval(expression);
|
|
25
|
+
res.json({ result });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Path traversal vulnerability
|
|
29
|
+
app.get('/file', (req, res) => {
|
|
30
|
+
const filename = req.query.filename;
|
|
31
|
+
const filePath = './data/' + filename;
|
|
32
|
+
fs.readFile(filePath, (err, data) => {
|
|
33
|
+
res.send(data);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Prototype pollution
|
|
38
|
+
function merge(target, source) {
|
|
39
|
+
for (let key in source) {
|
|
40
|
+
target[key] = source[key];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
app.post('/import', (req, res) => {
|
|
45
|
+
const user = { name: 'default' };
|
|
46
|
+
Object.prototype.admin = true;
|
|
47
|
+
merge(user, req.body);
|
|
48
|
+
res.json(user);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
app.listen(3000, () => {
|
|
52
|
+
console.log('Server running on port 3000'); // TODO: Move to config
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// TODO: Add authentication
|
|
56
|
+
// FIXME: Security review needed
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.7.0;
|
|
3
|
+
|
|
4
|
+
contract VulnerableContract {
|
|
5
|
+
mapping(address => uint) public balances;
|
|
6
|
+
address public owner;
|
|
7
|
+
|
|
8
|
+
// Using tx.origin for authentication
|
|
9
|
+
function withdraw() public {
|
|
10
|
+
require(tx.origin == msg.sender, "Not authorized");
|
|
11
|
+
uint amount = balances[msg.sender];
|
|
12
|
+
|
|
13
|
+
// External call before state update - reentrancy
|
|
14
|
+
(bool success, ) = msg.sender.call{value: amount}("");
|
|
15
|
+
|
|
16
|
+
if (success) {
|
|
17
|
+
balances[msg.sender] = 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Integer overflow risk
|
|
22
|
+
function addBalance(uint amount) public {
|
|
23
|
+
uint newBalance = balances[msg.sender] + amount;
|
|
24
|
+
balances[msg.sender] = newBalance;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Delegatecall risk
|
|
28
|
+
function upgrade(address newImpl) public {
|
|
29
|
+
(bool success, ) = address(this).delegatecall(
|
|
30
|
+
abi.encodeWithSignature("setImplementation(address)", newImpl)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Selfdestruct not protected
|
|
35
|
+
function destroy() public {
|
|
36
|
+
selfdestruct(payable(msg.sender));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const ScannerEngine = require('./src/scanner-engine');
|
|
7
|
+
const ConfigManager = require('./src/utils/config-manager');
|
|
8
|
+
const { version } = require('./package.json');
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('kobold-scan')
|
|
12
|
+
.description('Security vulnerability scanner for the KOBOLDS ecosystem')
|
|
13
|
+
.version(version);
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.command('scan <path>')
|
|
17
|
+
.description('Scan files for security vulnerabilities')
|
|
18
|
+
.option('-s, --severity <level>', 'Minimum severity level (critical|high|medium|low)', 'low')
|
|
19
|
+
.option('-f, --format <format>', 'Output format (terminal|json|markdown|sarif)', 'terminal')
|
|
20
|
+
.option('-o, --output <file>', 'Output file path (default: stdout)')
|
|
21
|
+
.option('-c, --config <path>', 'Path to custom config file')
|
|
22
|
+
.option('--include <patterns>', 'Include patterns (comma-separated)', '')
|
|
23
|
+
.option('--exclude <patterns>', 'Exclude patterns (comma-separated)', 'node_modules,\.git,build,dist')
|
|
24
|
+
.action(async (scanPath, options) => {
|
|
25
|
+
try {
|
|
26
|
+
const config = options.config
|
|
27
|
+
? ConfigManager.loadCustom(options.config)
|
|
28
|
+
: ConfigManager.loadDefault();
|
|
29
|
+
|
|
30
|
+
// Override config with CLI options
|
|
31
|
+
if (options.severity) config.severity = options.severity;
|
|
32
|
+
if (options.include) config.include = options.include.split(',');
|
|
33
|
+
if (options.exclude) config.exclude = options.exclude.split(',');
|
|
34
|
+
|
|
35
|
+
const engine = new ScannerEngine(config);
|
|
36
|
+
const results = await engine.scan(path.resolve(scanPath));
|
|
37
|
+
|
|
38
|
+
// Filter by severity (show this severity AND more severe)
|
|
39
|
+
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
40
|
+
const maxSeverityNum = severityOrder[options.severity] ?? 3;
|
|
41
|
+
|
|
42
|
+
results.vulnerabilities = results.vulnerabilities.filter(v => {
|
|
43
|
+
return severityOrder[v.severity] <= maxSeverityNum;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Output results
|
|
47
|
+
const Formatter = require(`./src/formatters/${options.format}`);
|
|
48
|
+
const output = Formatter.format(results);
|
|
49
|
+
|
|
50
|
+
if (options.output) {
|
|
51
|
+
fs.writeFileSync(options.output, output);
|
|
52
|
+
console.log(`Results written to: ${options.output}`);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(output);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Exit with error code if critical/high vulnerabilities found
|
|
58
|
+
const criticalCount = results.vulnerabilities.filter(v => v.severity === 'critical').length;
|
|
59
|
+
const highCount = results.vulnerabilities.filter(v => v.severity === 'high').length;
|
|
60
|
+
|
|
61
|
+
if (criticalCount > 0 || (options.severity === 'high' && highCount > 0)) {
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Error during scan:', error.message);
|
|
66
|
+
process.exit(2);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
program
|
|
71
|
+
.command('rules')
|
|
72
|
+
.description('List all available scanning rules')
|
|
73
|
+
.option('-l, --language <lang>', 'Filter by language (solidity|javascript|general)', 'all')
|
|
74
|
+
.action((options) => {
|
|
75
|
+
const RuleLoader = require('./src/utils/rule-loader');
|
|
76
|
+
const chalk = require('chalk');
|
|
77
|
+
|
|
78
|
+
const rules = RuleLoader.loadAllRules();
|
|
79
|
+
|
|
80
|
+
console.log(chalk.bold('\n🔍 KOBOLD-SCAN Available Rules\n'));
|
|
81
|
+
|
|
82
|
+
Object.entries(rules).forEach(([lang, langRules]) => {
|
|
83
|
+
if (options.language !== 'all' && lang !== options.language) return;
|
|
84
|
+
|
|
85
|
+
console.log(chalk.cyan.bold(`\n${lang.toUpperCase()}:`));
|
|
86
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
87
|
+
|
|
88
|
+
langRules.forEach(rule => {
|
|
89
|
+
const severityColor = {
|
|
90
|
+
critical: chalk.red.bold,
|
|
91
|
+
high: chalk.red,
|
|
92
|
+
medium: chalk.yellow,
|
|
93
|
+
low: chalk.gray
|
|
94
|
+
}[rule.severity] || chalk.white;
|
|
95
|
+
|
|
96
|
+
console.log(` ${severityColor(`[${rule.severity.toUpperCase()}]`)} ${rule.id}`);
|
|
97
|
+
console.log(` ${rule.name}`);
|
|
98
|
+
console.log(` ${chalk.gray(rule.description)}`);
|
|
99
|
+
if (rule.remediation) {
|
|
100
|
+
console.log(` ${chalk.green('💡')} ${chalk.italic(rule.remediation)}`);
|
|
101
|
+
}
|
|
102
|
+
console.log();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
program
|
|
108
|
+
.command('init')
|
|
109
|
+
.description('Initialize kobold-scan configuration in current directory')
|
|
110
|
+
.option('-f, --force', 'Overwrite existing config file', false)
|
|
111
|
+
.action((options) => {
|
|
112
|
+
const configPath = path.join(process.cwd(), 'kobold-scan.json');
|
|
113
|
+
|
|
114
|
+
if (fs.existsSync(configPath) && !options.force) {
|
|
115
|
+
console.log('Config file already exists. Use --force to overwrite.');
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const defaultConfig = ConfigManager.getDefaultConfig();
|
|
120
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
|
|
121
|
+
|
|
122
|
+
console.log(`✅ Configuration file created: ${configPath}`);
|
|
123
|
+
console.log('\nYou can now customize:');
|
|
124
|
+
console.log(' • Severity thresholds');
|
|
125
|
+
console.log(' • Enabled/disabled rules');
|
|
126
|
+
console.log(' • Ignore patterns');
|
|
127
|
+
console.log(' • Custom rule paths');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
program.parse();
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kobold-scan",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"node_modules/ansi-styles": {
|
|
8
|
+
"version": "4.3.0",
|
|
9
|
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
10
|
+
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"color-convert": "^2.0.1"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=8"
|
|
17
|
+
},
|
|
18
|
+
"funding": {
|
|
19
|
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"node_modules/balanced-match": {
|
|
23
|
+
"version": "1.0.2",
|
|
24
|
+
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
25
|
+
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
|
26
|
+
"license": "MIT"
|
|
27
|
+
},
|
|
28
|
+
"node_modules/brace-expansion": {
|
|
29
|
+
"version": "2.0.2",
|
|
30
|
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
|
31
|
+
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"balanced-match": "^1.0.0"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"node_modules/chalk": {
|
|
38
|
+
"version": "4.1.2",
|
|
39
|
+
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
|
40
|
+
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"ansi-styles": "^4.1.0",
|
|
44
|
+
"supports-color": "^7.1.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=10"
|
|
48
|
+
},
|
|
49
|
+
"funding": {
|
|
50
|
+
"url": "https://github.com/chalk/chalk?sponsor=1"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"node_modules/color-convert": {
|
|
54
|
+
"version": "2.0.1",
|
|
55
|
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
56
|
+
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"color-name": "~1.1.4"
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=7.0.0"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"node_modules/color-name": {
|
|
66
|
+
"version": "1.1.4",
|
|
67
|
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
68
|
+
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
69
|
+
"license": "MIT"
|
|
70
|
+
},
|
|
71
|
+
"node_modules/commander": {
|
|
72
|
+
"version": "9.5.0",
|
|
73
|
+
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
|
74
|
+
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
|
75
|
+
"license": "MIT",
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": "^12.20.0 || >=14"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"node_modules/fs.realpath": {
|
|
81
|
+
"version": "1.0.0",
|
|
82
|
+
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
83
|
+
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
|
84
|
+
"license": "ISC"
|
|
85
|
+
},
|
|
86
|
+
"node_modules/glob": {
|
|
87
|
+
"version": "8.1.0",
|
|
88
|
+
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
|
89
|
+
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
|
90
|
+
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
|
91
|
+
"license": "ISC",
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"fs.realpath": "^1.0.0",
|
|
94
|
+
"inflight": "^1.0.4",
|
|
95
|
+
"inherits": "2",
|
|
96
|
+
"minimatch": "^5.0.1",
|
|
97
|
+
"once": "^1.3.0"
|
|
98
|
+
},
|
|
99
|
+
"engines": {
|
|
100
|
+
"node": ">=12"
|
|
101
|
+
},
|
|
102
|
+
"funding": {
|
|
103
|
+
"url": "https://github.com/sponsors/isaacs"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"node_modules/has-flag": {
|
|
107
|
+
"version": "4.0.0",
|
|
108
|
+
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
109
|
+
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
|
110
|
+
"license": "MIT",
|
|
111
|
+
"engines": {
|
|
112
|
+
"node": ">=8"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"node_modules/inflight": {
|
|
116
|
+
"version": "1.0.6",
|
|
117
|
+
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
118
|
+
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
|
119
|
+
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
|
120
|
+
"license": "ISC",
|
|
121
|
+
"dependencies": {
|
|
122
|
+
"once": "^1.3.0",
|
|
123
|
+
"wrappy": "1"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"node_modules/inherits": {
|
|
127
|
+
"version": "2.0.4",
|
|
128
|
+
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
129
|
+
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
|
130
|
+
"license": "ISC"
|
|
131
|
+
},
|
|
132
|
+
"node_modules/minimatch": {
|
|
133
|
+
"version": "5.1.6",
|
|
134
|
+
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
|
135
|
+
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
|
136
|
+
"license": "ISC",
|
|
137
|
+
"dependencies": {
|
|
138
|
+
"brace-expansion": "^2.0.1"
|
|
139
|
+
},
|
|
140
|
+
"engines": {
|
|
141
|
+
"node": ">=10"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"node_modules/once": {
|
|
145
|
+
"version": "1.4.0",
|
|
146
|
+
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
147
|
+
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
|
148
|
+
"license": "ISC",
|
|
149
|
+
"dependencies": {
|
|
150
|
+
"wrappy": "1"
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"node_modules/supports-color": {
|
|
154
|
+
"version": "7.2.0",
|
|
155
|
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
|
156
|
+
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
157
|
+
"license": "MIT",
|
|
158
|
+
"dependencies": {
|
|
159
|
+
"has-flag": "^4.0.0"
|
|
160
|
+
},
|
|
161
|
+
"engines": {
|
|
162
|
+
"node": ">=8"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"node_modules/wrappy": {
|
|
166
|
+
"version": "1.0.2",
|
|
167
|
+
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
168
|
+
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
|
169
|
+
"license": "ISC"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|