0xkobold 0.5.0 → 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.
Files changed (128) hide show
  1. package/dist/package.json +5 -4
  2. package/dist/src/agent/types/definitions.js +2 -1
  3. package/dist/src/agent/types/definitions.js.map +1 -1
  4. package/dist/src/cli/commands/setup.js +0 -3
  5. package/dist/src/cli/commands/setup.js.map +1 -1
  6. package/dist/src/config/loader.js +0 -3
  7. package/dist/src/config/loader.js.map +1 -1
  8. package/dist/src/event-bus/index.js.map +1 -1
  9. package/dist/src/extensions/core/agent-orchestrator-extension.js +19 -2
  10. package/dist/src/extensions/core/agent-orchestrator-extension.js.map +1 -1
  11. package/dist/src/extensions/core/auto-security-scan-extension.js +41 -0
  12. package/dist/src/extensions/core/auto-security-scan-extension.js.map +1 -0
  13. package/dist/src/extensions/core/task-manager-extension.js +20 -3
  14. package/dist/src/extensions/core/task-manager-extension.js.map +1 -1
  15. package/dist/src/index.js +0 -1
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/pi-config.js +2 -0
  18. package/dist/src/pi-config.js.map +1 -1
  19. package/package.json +5 -4
  20. package/skills/kobold-scan-skill/README.md +218 -0
  21. package/skills/kobold-scan-skill/config/default.json +14 -0
  22. package/skills/kobold-scan-skill/examples/vulnerable.js +56 -0
  23. package/skills/kobold-scan-skill/examples/vulnerable.sol +38 -0
  24. package/skills/kobold-scan-skill/index.js +130 -0
  25. package/skills/kobold-scan-skill/node_modules/.package-lock.json +172 -0
  26. package/skills/kobold-scan-skill/node_modules/ansi-styles/index.d.ts +345 -0
  27. package/skills/kobold-scan-skill/node_modules/ansi-styles/index.js +163 -0
  28. package/skills/kobold-scan-skill/node_modules/ansi-styles/license +9 -0
  29. package/skills/kobold-scan-skill/node_modules/ansi-styles/package.json +56 -0
  30. package/skills/kobold-scan-skill/node_modules/ansi-styles/readme.md +152 -0
  31. package/skills/kobold-scan-skill/node_modules/balanced-match/.github/FUNDING.yml +2 -0
  32. package/skills/kobold-scan-skill/node_modules/balanced-match/LICENSE.md +21 -0
  33. package/skills/kobold-scan-skill/node_modules/balanced-match/README.md +97 -0
  34. package/skills/kobold-scan-skill/node_modules/balanced-match/index.js +62 -0
  35. package/skills/kobold-scan-skill/node_modules/balanced-match/package.json +48 -0
  36. package/skills/kobold-scan-skill/node_modules/brace-expansion/.github/FUNDING.yml +2 -0
  37. package/skills/kobold-scan-skill/node_modules/brace-expansion/LICENSE +21 -0
  38. package/skills/kobold-scan-skill/node_modules/brace-expansion/README.md +135 -0
  39. package/skills/kobold-scan-skill/node_modules/brace-expansion/index.js +203 -0
  40. package/skills/kobold-scan-skill/node_modules/brace-expansion/package.json +49 -0
  41. package/skills/kobold-scan-skill/node_modules/chalk/index.d.ts +415 -0
  42. package/skills/kobold-scan-skill/node_modules/chalk/license +9 -0
  43. package/skills/kobold-scan-skill/node_modules/chalk/package.json +68 -0
  44. package/skills/kobold-scan-skill/node_modules/chalk/readme.md +341 -0
  45. package/skills/kobold-scan-skill/node_modules/chalk/source/index.js +229 -0
  46. package/skills/kobold-scan-skill/node_modules/chalk/source/templates.js +134 -0
  47. package/skills/kobold-scan-skill/node_modules/chalk/source/util.js +39 -0
  48. package/skills/kobold-scan-skill/node_modules/color-convert/CHANGELOG.md +54 -0
  49. package/skills/kobold-scan-skill/node_modules/color-convert/LICENSE +21 -0
  50. package/skills/kobold-scan-skill/node_modules/color-convert/README.md +68 -0
  51. package/skills/kobold-scan-skill/node_modules/color-convert/conversions.js +839 -0
  52. package/skills/kobold-scan-skill/node_modules/color-convert/index.js +81 -0
  53. package/skills/kobold-scan-skill/node_modules/color-convert/package.json +48 -0
  54. package/skills/kobold-scan-skill/node_modules/color-convert/route.js +97 -0
  55. package/skills/kobold-scan-skill/node_modules/color-name/LICENSE +8 -0
  56. package/skills/kobold-scan-skill/node_modules/color-name/README.md +11 -0
  57. package/skills/kobold-scan-skill/node_modules/color-name/index.js +152 -0
  58. package/skills/kobold-scan-skill/node_modules/color-name/package.json +28 -0
  59. package/skills/kobold-scan-skill/node_modules/commander/LICENSE +22 -0
  60. package/skills/kobold-scan-skill/node_modules/commander/Readme.md +1129 -0
  61. package/skills/kobold-scan-skill/node_modules/commander/esm.mjs +16 -0
  62. package/skills/kobold-scan-skill/node_modules/commander/index.js +27 -0
  63. package/skills/kobold-scan-skill/node_modules/commander/lib/argument.js +147 -0
  64. package/skills/kobold-scan-skill/node_modules/commander/lib/command.js +2179 -0
  65. package/skills/kobold-scan-skill/node_modules/commander/lib/error.js +45 -0
  66. package/skills/kobold-scan-skill/node_modules/commander/lib/help.js +461 -0
  67. package/skills/kobold-scan-skill/node_modules/commander/lib/option.js +326 -0
  68. package/skills/kobold-scan-skill/node_modules/commander/lib/suggestSimilar.js +100 -0
  69. package/skills/kobold-scan-skill/node_modules/commander/package-support.json +16 -0
  70. package/skills/kobold-scan-skill/node_modules/commander/package.json +80 -0
  71. package/skills/kobold-scan-skill/node_modules/commander/typings/index.d.ts +891 -0
  72. package/skills/kobold-scan-skill/node_modules/fs.realpath/LICENSE +43 -0
  73. package/skills/kobold-scan-skill/node_modules/fs.realpath/README.md +33 -0
  74. package/skills/kobold-scan-skill/node_modules/fs.realpath/index.js +66 -0
  75. package/skills/kobold-scan-skill/node_modules/fs.realpath/old.js +303 -0
  76. package/skills/kobold-scan-skill/node_modules/fs.realpath/package.json +26 -0
  77. package/skills/kobold-scan-skill/node_modules/glob/LICENSE +15 -0
  78. package/skills/kobold-scan-skill/node_modules/glob/README.md +399 -0
  79. package/skills/kobold-scan-skill/node_modules/glob/common.js +244 -0
  80. package/skills/kobold-scan-skill/node_modules/glob/glob.js +790 -0
  81. package/skills/kobold-scan-skill/node_modules/glob/package.json +55 -0
  82. package/skills/kobold-scan-skill/node_modules/glob/sync.js +486 -0
  83. package/skills/kobold-scan-skill/node_modules/has-flag/index.d.ts +39 -0
  84. package/skills/kobold-scan-skill/node_modules/has-flag/index.js +8 -0
  85. package/skills/kobold-scan-skill/node_modules/has-flag/license +9 -0
  86. package/skills/kobold-scan-skill/node_modules/has-flag/package.json +46 -0
  87. package/skills/kobold-scan-skill/node_modules/has-flag/readme.md +89 -0
  88. package/skills/kobold-scan-skill/node_modules/inflight/LICENSE +15 -0
  89. package/skills/kobold-scan-skill/node_modules/inflight/README.md +37 -0
  90. package/skills/kobold-scan-skill/node_modules/inflight/inflight.js +54 -0
  91. package/skills/kobold-scan-skill/node_modules/inflight/package.json +29 -0
  92. package/skills/kobold-scan-skill/node_modules/inherits/LICENSE +16 -0
  93. package/skills/kobold-scan-skill/node_modules/inherits/README.md +42 -0
  94. package/skills/kobold-scan-skill/node_modules/inherits/inherits.js +9 -0
  95. package/skills/kobold-scan-skill/node_modules/inherits/inherits_browser.js +27 -0
  96. package/skills/kobold-scan-skill/node_modules/inherits/package.json +29 -0
  97. package/skills/kobold-scan-skill/node_modules/minimatch/LICENSE +15 -0
  98. package/skills/kobold-scan-skill/node_modules/minimatch/README.md +259 -0
  99. package/skills/kobold-scan-skill/node_modules/minimatch/lib/path.js +4 -0
  100. package/skills/kobold-scan-skill/node_modules/minimatch/minimatch.js +944 -0
  101. package/skills/kobold-scan-skill/node_modules/minimatch/package.json +35 -0
  102. package/skills/kobold-scan-skill/node_modules/once/LICENSE +15 -0
  103. package/skills/kobold-scan-skill/node_modules/once/README.md +79 -0
  104. package/skills/kobold-scan-skill/node_modules/once/once.js +42 -0
  105. package/skills/kobold-scan-skill/node_modules/once/package.json +33 -0
  106. package/skills/kobold-scan-skill/node_modules/supports-color/browser.js +5 -0
  107. package/skills/kobold-scan-skill/node_modules/supports-color/index.js +135 -0
  108. package/skills/kobold-scan-skill/node_modules/supports-color/license +9 -0
  109. package/skills/kobold-scan-skill/node_modules/supports-color/package.json +53 -0
  110. package/skills/kobold-scan-skill/node_modules/supports-color/readme.md +76 -0
  111. package/skills/kobold-scan-skill/node_modules/wrappy/LICENSE +15 -0
  112. package/skills/kobold-scan-skill/node_modules/wrappy/README.md +36 -0
  113. package/skills/kobold-scan-skill/node_modules/wrappy/package.json +29 -0
  114. package/skills/kobold-scan-skill/node_modules/wrappy/wrappy.js +33 -0
  115. package/skills/kobold-scan-skill/package-lock.json +188 -0
  116. package/skills/kobold-scan-skill/package.json +34 -0
  117. package/skills/kobold-scan-skill/rules/general.json +30 -0
  118. package/skills/kobold-scan-skill/rules/javascript.json +44 -0
  119. package/skills/kobold-scan-skill/rules/solidity.json +30 -0
  120. package/skills/kobold-scan-skill/src/formatters/json.js +7 -0
  121. package/skills/kobold-scan-skill/src/formatters/terminal.js +66 -0
  122. package/skills/kobold-scan-skill/src/scanner-engine.js +139 -0
  123. package/skills/kobold-scan-skill/src/scanners/general.js +83 -0
  124. package/skills/kobold-scan-skill/src/scanners/javascript.js +182 -0
  125. package/skills/kobold-scan-skill/src/scanners/solidity.js +131 -0
  126. package/skills/kobold-scan-skill/src/utils/config-manager.js +37 -0
  127. package/skills/kobold-scan-skill/src/utils/rule-loader.js +24 -0
  128. package/skills/kobold-scan.ts +107 -0
@@ -0,0 +1,182 @@
1
+ class JavaScriptScanner {
2
+ constructor(config) {
3
+ this.config = config;
4
+ this.exclusions = config.exclusions || {
5
+ tokenNames: ['KOBOLDS', 'DRAKIN', 'TRIDENT', 'MLTL', 'WETH', 'USDC', 'ETH'],
6
+ minSecretLength: 20, // Skip short strings (not real secrets)
7
+ allowedInComments: true
8
+ };
9
+ }
10
+
11
+ scan(content, filePath) {
12
+ const vulnerabilities = [];
13
+ const lines = content.split('\n');
14
+
15
+ // Skip test/example files
16
+ if (this.isTestFile(filePath)) {
17
+ return [];
18
+ }
19
+
20
+ // Skip scanner rule files (they define patterns, not vulnerabilities)
21
+ if (filePath.includes('/scanners/') || filePath.includes('/rules/')) {
22
+ return [];
23
+ }
24
+
25
+ lines.forEach((line, index) => {
26
+ // Skip comments (lines starting with //)
27
+ if (this.isComment(line)) {
28
+ return;
29
+ }
30
+
31
+ // JS-001: eval() usage
32
+ this.checkEval(line, index, filePath, vulnerabilities);
33
+
34
+ // JS-002: Hardcoded secrets (with exclusions)
35
+ this.checkSecrets(line, index, filePath, vulnerabilities);
36
+
37
+ // JS-004: SQL injection
38
+ this.checkSQLInjection(line, index, filePath, vulnerabilities);
39
+
40
+ // JS-005: Path traversal
41
+ this.checkPathTraversal(line, index, filePath, vulnerabilities);
42
+
43
+ // JS-007: console.log
44
+ this.checkConsoleLog(line, index, filePath, vulnerabilities);
45
+
46
+ // JS-006: Prototype pollution
47
+ this.checkPrototypePollution(line, index, filePath, vulnerabilities);
48
+ });
49
+
50
+ return vulnerabilities;
51
+ }
52
+
53
+ isTestFile(filePath) {
54
+ const testPatterns = [
55
+ /\/examples\//,
56
+ /\/test\//,
57
+ /\/tests\//,
58
+ /\.test\./,
59
+ /\.spec\./,
60
+ /\/fixtures\//,
61
+ /\/mocks\//
62
+ ];
63
+ return testPatterns.some(p => p.test(filePath));
64
+ }
65
+
66
+ isComment(line) {
67
+ return /^\s*\/\//.test(line) || /^\s*\/\*/.test(line);
68
+ }
69
+
70
+ checkEval(line, index, filePath, vulns) {
71
+ const evalPattern = /\beval\s*\(/;
72
+ if (evalPattern.test(line)) {
73
+ vulns.push({
74
+ rule: 'JS-001',
75
+ severity: 'critical',
76
+ message: 'Dangerous eval() usage - code injection risk',
77
+ file: filePath,
78
+ line: index + 1,
79
+ code: line.trim()
80
+ });
81
+ }
82
+ }
83
+
84
+ checkSecrets(line, index, filePath, vulns) {
85
+ // Improved secret pattern - requires proper key format
86
+ const secretPattern = /(api[_-]?key|apikey|secret[_-]?key|secretkey|private[_-]?key|privatekey)\s*[:=]\s*["']([a-zA-Z0-9_\-]{20,})["']/i;
87
+
88
+ const match = line.match(secretPattern);
89
+ if (match) {
90
+ const value = match[2];
91
+
92
+ // Skip if matches known token names
93
+ if (this.exclusions.tokenNames.includes(value)) {
94
+ return;
95
+ }
96
+
97
+ // Skip if too short (not a real secret)
98
+ if (value.length < this.exclusions.minSecretLength) {
99
+ return;
100
+ }
101
+
102
+ // Skip if looks like an address (0x...)
103
+ if (value.startsWith('0x')) {
104
+ return;
105
+ }
106
+
107
+ vulns.push({
108
+ rule: 'JS-002',
109
+ severity: 'critical',
110
+ message: 'Hardcoded secret/credential detected',
111
+ file: filePath,
112
+ line: index + 1,
113
+ code: line.trim()
114
+ });
115
+ }
116
+ }
117
+
118
+ checkSQLInjection(line, index, filePath, vulns) {
119
+ // Only flag actual concatenation in query strings
120
+ const sqlPattern = /(query|execute|exec)\s*\(.*["'].*(SELECT|INSERT|UPDATE|DELETE).*\+.*\$|\+.*["'].*(SELECT|INSERT|UPDATE|DELETE)/i;
121
+
122
+ if (sqlPattern.test(line)) {
123
+ vulns.push({
124
+ rule: 'JS-004',
125
+ severity: 'high',
126
+ message: 'Potential SQL injection via string concatenation',
127
+ file: filePath,
128
+ line: index + 1,
129
+ code: line.trim()
130
+ });
131
+ }
132
+ }
133
+
134
+ checkPathTraversal(line, index, filePath, vulns) {
135
+ const pathPattern = /fs\.(readFile|writeFile|createReadStream|unlink)\s*\([^)]*\+\s*(req|request|params|body)\.|\.\.[\/\\].*(req|request|params)/;
136
+
137
+ if (pathPattern.test(line)) {
138
+ vulns.push({
139
+ rule: 'JS-005',
140
+ severity: 'high',
141
+ message: 'Path traversal risk - user input in file path',
142
+ file: filePath,
143
+ line: index + 1,
144
+ code: line.trim()
145
+ });
146
+ }
147
+ }
148
+
149
+ checkConsoleLog(line, index, filePath, vulns) {
150
+ // Skip console logs that just log errors (common pattern)
151
+ const consolePattern = /console\.(log|debug|warn|error)\s*\(/;
152
+ const isErrorLog = /console\.error\s*\(\s*(err|error|e)\s*\)/i;
153
+
154
+ if (consolePattern.test(line) && !isErrorLog.test(line)) {
155
+ vulns.push({
156
+ rule: 'JS-007',
157
+ severity: 'low',
158
+ message: 'console.log left in production code',
159
+ file: filePath,
160
+ line: index + 1,
161
+ code: line.trim()
162
+ });
163
+ }
164
+ }
165
+
166
+ checkPrototypePollution(line, index, filePath, vulns) {
167
+ const protoPattern = /Object\.prototype\.__proto__|Object\.prototype\.constructor\s*=/;
168
+
169
+ if (protoPattern.test(line)) {
170
+ vulns.push({
171
+ rule: 'JS-006',
172
+ severity: 'high',
173
+ message: 'Prototype pollution risk detected',
174
+ file: filePath,
175
+ line: index + 1,
176
+ code: line.trim()
177
+ });
178
+ }
179
+ }
180
+ }
181
+
182
+ module.exports = JavaScriptScanner;
@@ -0,0 +1,131 @@
1
+ class SolidityScanner {
2
+ constructor(config) {
3
+ this.config = config;
4
+ }
5
+
6
+ scan(content, filePath) {
7
+ const vulnerabilities = [];
8
+ const lines = content.split('\n');
9
+
10
+ // Skip example/test files
11
+ if (filePath.includes('/examples/') || filePath.includes('/test/')) {
12
+ return [];
13
+ }
14
+
15
+ lines.forEach((line, index) => {
16
+ // Skip comments
17
+ if (this.isComment(line)) {
18
+ return;
19
+ }
20
+
21
+ // SOL-004: tx.origin usage
22
+ this.checkTxOrigin(line, index, filePath, vulnerabilities);
23
+
24
+ // SOL-001: Reentrancy
25
+ this.checkReentrancy(line, index, filePath, vulnerabilities);
26
+
27
+ // SOL-006: Delegatecall injection
28
+ this.checkDelegatecall(line, index, filePath, vulnerabilities);
29
+
30
+ // SOL-003: Overflow (only flag in pre-0.8 versions)
31
+ this.checkOverflow(line, index, filePath, content, vulnerabilities);
32
+ });
33
+
34
+ return vulnerabilities;
35
+ }
36
+
37
+ isComment(line) {
38
+ return /^\s*\/\//.test(line) || /^\s*\/\*/.test(line) || /\*\//.test(line);
39
+ }
40
+
41
+ checkTxOrigin(line, index, filePath, vulns) {
42
+ const txOriginPattern = /tx\.origin/;
43
+
44
+ // Skip if it's in a comment about the vulnerability
45
+ if (line.includes('phishing') || line.includes('authentication')) {
46
+ // This is likely a comment warning about the issue
47
+ return;
48
+ }
49
+
50
+ if (txOriginPattern.test(line)) {
51
+ // Check if it's actually used for auth (require statement)
52
+ if (line.includes('require') || line.includes('==') || line.includes('!=')) {
53
+ vulns.push({
54
+ rule: 'SOL-004',
55
+ severity: 'critical',
56
+ message: 'tx.origin used for authentication - phishing risk',
57
+ file: filePath,
58
+ line: index + 1,
59
+ code: line.trim()
60
+ });
61
+ }
62
+ }
63
+ }
64
+
65
+ checkReentrancy(line, index, filePath, vulns) {
66
+ // Look for external call patterns that could be reentrant
67
+ const externalCallPattern = /\.call\{value:[^}]+\}\([^)]*\)/;
68
+ const transferPattern = /\.transfer\s*\(/;
69
+ const sendPattern = /\.send\s*\(/;
70
+
71
+ if (externalCallPattern.test(line) && !transferPattern.test(line) && !sendPattern.test(line)) {
72
+ // Check if state is updated AFTER the call (reentrancy pattern)
73
+ // This is a simplified check - real detection needs flow analysis
74
+ vulns.push({
75
+ rule: 'SOL-001',
76
+ severity: 'high', // Downgrade from critical unless we confirm pattern
77
+ message: 'External call detected - verify state updates happen before, not after',
78
+ file: filePath,
79
+ line: index + 1,
80
+ code: line.trim()
81
+ });
82
+ }
83
+ }
84
+
85
+ checkDelegatecall(line, index, filePath, vulns) {
86
+ const delegatecallPattern = /\.delegatecall\s*\(/;
87
+
88
+ if (delegatecallPattern.test(line)) {
89
+ // Check if address is user-controlled (contains msg.sender or parameter)
90
+ if (line.includes('msg.sender') || line.includes('address(') || /\b[A-Za-z]+\)/.test(line)) {
91
+ vulns.push({
92
+ rule: 'SOL-006',
93
+ severity: 'high',
94
+ message: 'Delegatecall to potentially user-controlled address',
95
+ file: filePath,
96
+ line: index + 1,
97
+ code: line.trim()
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ checkOverflow(line, index, filePath, content, vulns) {
104
+ // Only flag for Solidity < 0.8 which doesn't have built-in checks
105
+ const pragmaMatch = content.match(/pragma\s+solidity\s+\^?(\d+)\.(\d+)/);
106
+ if (!pragmaMatch) return;
107
+
108
+ const major = parseInt(pragmaMatch[1]);
109
+ const minor = parseInt(pragmaMatch[2]);
110
+
111
+ // Solidity 0.8+ has built-in overflow checks
112
+ if (major > 0 || (major === 0 && minor >= 8)) {
113
+ return;
114
+ }
115
+
116
+ const overflowPattern = /uint\d*\s+\w+\s*=\s*\w+\s*[\+\-\*]\s*\w+/;
117
+
118
+ if (overflowPattern.test(line)) {
119
+ vulns.push({
120
+ rule: 'SOL-003',
121
+ severity: 'medium', // Downgrade since it's context-dependent
122
+ message: 'Potential integer overflow (pre-Solidity 0.8) - consider SafeMath',
123
+ file: filePath,
124
+ line: index + 1,
125
+ code: line.trim()
126
+ });
127
+ }
128
+ }
129
+ }
130
+
131
+ module.exports = SolidityScanner;
@@ -0,0 +1,37 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const DEFAULT_CONFIG = {
5
+ severity: 'low',
6
+ include: ['**/*'],
7
+ exclude: ['node_modules/**', '.git/**', 'build/**', 'dist/**', '**/*.min.js'],
8
+ rules: {
9
+ solidity: { enabled: true },
10
+ javascript: { enabled: true },
11
+ general: { enabled: true }
12
+ },
13
+ output: {
14
+ showCodeSnippets: true,
15
+ maxIssuesPerRule: 50
16
+ }
17
+ };
18
+
19
+ class ConfigManager {
20
+ static loadDefault() {
21
+ return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
22
+ }
23
+
24
+ static loadCustom(configPath) {
25
+ if (!fs.existsSync(configPath)) {
26
+ throw new Error(`Config file not found: ${configPath}`);
27
+ }
28
+ const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
29
+ return { ...DEFAULT_CONFIG, ...userConfig };
30
+ }
31
+
32
+ static getDefaultConfig() {
33
+ return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
34
+ }
35
+ }
36
+
37
+ module.exports = ConfigManager;
@@ -0,0 +1,24 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const RULES_DIR = path.join(__dirname, '../../rules');
5
+
6
+ class RuleLoader {
7
+ static loadRules(language) {
8
+ const ruleFile = path.join(RULES_DIR, `${language}.json`);
9
+ if (!fs.existsSync(ruleFile)) {
10
+ return [];
11
+ }
12
+ return JSON.parse(fs.readFileSync(ruleFile, 'utf8'));
13
+ }
14
+
15
+ static loadAllRules() {
16
+ return {
17
+ solidity: this.loadRules('solidity'),
18
+ javascript: this.loadRules('javascript'),
19
+ general: this.loadRules('general')
20
+ };
21
+ }
22
+ }
23
+
24
+ module.exports = RuleLoader;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * 🔍 Kobold Scan Skill
3
+ *
4
+ * Security vulnerability scanner for 0xKobold projects.
5
+ * Scans code for secrets, vulnerabilities, and anti-patterns.
6
+ *
7
+ * This is a wrapper around the kobold-scan tool from
8
+ * https://git.kobolds.run/kobolds/kobold-scan-skill
9
+ */
10
+
11
+ import { Skill } from '../src/skills/types';
12
+ import { execSync } from 'child_process';
13
+ import { existsSync } from 'fs';
14
+ import { resolve } from 'path';
15
+
16
+ export const koboldScan: Skill = {
17
+ name: 'koboldScan',
18
+ description: 'Security vulnerability scanner for JavaScript, Node.js, and Solidity codebases. Detects hardcoded secrets, SQL injection, path traversal, eval usage, and smart contract vulnerabilities.',
19
+ risk: 'safe',
20
+
21
+ toolDefinition: {
22
+ type: 'function',
23
+ function: {
24
+ name: 'koboldScan',
25
+ description: 'Scan code for security vulnerabilities and anti-patterns. Detects secrets, injection vulnerabilities, and Solidity issues.',
26
+ parameters: {
27
+ type: 'object',
28
+ properties: {
29
+ path: {
30
+ type: 'string',
31
+ description: 'Path to directory or file to scan (relative to workspace)'
32
+ },
33
+ severity: {
34
+ type: 'string',
35
+ enum: ['critical', 'high', 'medium', 'low'],
36
+ description: 'Minimum severity level to report'
37
+ },
38
+ format: {
39
+ type: 'string',
40
+ enum: ['terminal', 'json', 'markdown'],
41
+ description: 'Output format'
42
+ }
43
+ },
44
+ required: ['path']
45
+ }
46
+ }
47
+ },
48
+
49
+ async execute(args: { path: string; severity?: string; format?: string }) {
50
+ const scanPath = resolve(args.path);
51
+
52
+ if (!existsSync(scanPath)) {
53
+ return {
54
+ success: false,
55
+ error: `Path not found: ${args.path}`
56
+ };
57
+ }
58
+
59
+ const severity = args.severity || 'low';
60
+ const format = args.format || 'json';
61
+
62
+ try {
63
+ // Check if kobold-scan is available
64
+ const cmd = `cd /home/moika/Documents/code/0xKobolds/skills/kobold-scan-skill && node index.js scan "${scanPath}" --severity ${severity} --format ${format}`;
65
+ const result = execSync(cmd, { encoding: 'utf-8', timeout: 60000 });
66
+
67
+ if (format === 'json') {
68
+ const parsed = JSON.parse(result);
69
+ return {
70
+ success: true,
71
+ data: parsed,
72
+ summary: `${parsed.summary?.filesScanned || 0} files scanned, ${parsed.summary?.issuesFound || 0} issues found`
73
+ };
74
+ }
75
+
76
+ return {
77
+ success: true,
78
+ data: result
79
+ };
80
+ } catch (error: any) {
81
+ // Scanner exits with code 1 if issues found, but still outputs valid result
82
+ if (error.stdout) {
83
+ try {
84
+ if (format === 'json') {
85
+ const parsed = JSON.parse(error.stdout);
86
+ return {
87
+ success: true,
88
+ data: parsed,
89
+ summary: `${parsed.summary?.filesScanned || 0} files scanned, ${parsed.summary?.issuesFound || 0} issues found`,
90
+ issues: parsed.vulnerabilities
91
+ };
92
+ }
93
+ return { success: true, data: error.stdout };
94
+ } catch {
95
+ return { success: true, data: error.stdout };
96
+ }
97
+ }
98
+
99
+ return {
100
+ success: false,
101
+ error: `Scan failed: ${error.message}`
102
+ };
103
+ }
104
+ }
105
+ };
106
+
107
+ export default koboldScan;