@authora/agent-audit 0.1.0 → 0.1.1

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/scanner.js CHANGED
@@ -54,18 +54,33 @@ export async function scanDirectory(dir) {
54
54
  let hasAuditLog = false;
55
55
  let hasApprovals = false;
56
56
  const files = walkDir(dir);
57
- for (const file of files) {
57
+ // Skip non-backend files (frontend components, tests, docs, configs)
58
+ const SKIP_PATTERNS = [
59
+ /\.(test|spec|stories)\.[tj]sx?$/,
60
+ /\/__(tests|mocks|fixtures)__\//,
61
+ /\/(web|ui|frontend|app)\/src\/(components|pages|hooks|stores|lib)\//,
62
+ /\.d\.ts$/,
63
+ /\.(md|mdx|txt|svg|css|scss|html)$/,
64
+ /package\.json$/,
65
+ /package-lock\.json$/,
66
+ /tsconfig.*\.json$/,
67
+ ];
68
+ const backendFiles = files.filter((f) => {
69
+ const rel = f.replace(dir + "/", "");
70
+ return !SKIP_PATTERNS.some((p) => p.test(rel));
71
+ });
72
+ for (const file of backendFiles) {
58
73
  const content = readFile(file);
59
74
  if (!content)
60
75
  continue;
61
76
  const lower = content.toLowerCase();
62
77
  const relPath = file.replace(dir + "/", "");
63
- // Detect agents
64
- if (/\bagent\b/i.test(content) && (/\bcreate.*agent|agent.*config|new.*agent|agent.*class\b/i.test(content))) {
78
+ // Detect agents -- only in backend code with real agent patterns
79
+ if (/\bagent\b/i.test(content) && (/\bcreateAgent|AgentConfig|new.*Agent\(|runAgent|agentWorkflow\b/i.test(content))) {
65
80
  agents++;
66
81
  }
67
- // Detect MCP servers
68
- if (/mcp.*server|mcpserver|model.*context.*protocol/i.test(lower)) {
82
+ // Detect MCP servers -- only files that actually create/configure MCP servers
83
+ if (/new.*Server|createServer|McpServer|startServer/i.test(content) && /mcp|model.*context.*protocol/i.test(lower)) {
69
84
  mcpServers++;
70
85
  }
71
86
  // Check for identity layer
@@ -120,27 +135,30 @@ export async function scanDirectory(dir) {
120
135
  }
121
136
  }
122
137
  // --- WARNING: MCP server without auth ---
123
- if (/mcp.*server|createServer/i.test(content) && !/auth|authentication|authorization|token|apiKey/i.test(content)) {
138
+ // Only flag files that actually create/start MCP servers, not type defs or configs
139
+ if (/new.*Server|createServer|McpServer/i.test(content) && /mcp/i.test(lower) && !/auth|authentication|authorization|token|apiKey|signature/i.test(content)) {
124
140
  findings.push({
125
141
  severity: "warning",
126
142
  category: "mcp",
127
- message: "MCP server detected without visible auth configuration",
143
+ message: "MCP server created without visible auth configuration",
128
144
  file: relPath,
129
145
  fix: "Add authentication to your MCP server (API key, JWT, or Ed25519 signature verification)",
130
146
  });
131
147
  }
132
148
  // --- WARNING: Broad agent permissions ---
133
- if (/\*.*permission|admin.*role|full.*access|sudo|root/i.test(content) && /agent/i.test(content)) {
149
+ // Only flag if it's clearly giving an agent admin/wildcard access
150
+ if (/permissions.*\[.*["']\*["']|role.*["']admin["']|full.*access.*agent/i.test(content)) {
134
151
  findings.push({
135
152
  severity: "warning",
136
153
  category: "permissions",
137
- message: "Agent may have overly broad permissions",
154
+ message: "Agent configured with overly broad permissions",
138
155
  file: relPath,
139
156
  fix: "Apply least-privilege: give agents only the permissions they need for their specific task",
140
157
  });
141
158
  }
142
159
  // --- WARNING: No error handling on tool calls ---
143
- if (/tool.*call|callTool|execute.*tool/i.test(content) && !/try|catch|error/i.test(content)) {
160
+ // Only flag actual tool execution code, not type definitions or prompts
161
+ if (/callTool\(|executeTool\(|tool\.execute\(/i.test(content) && !/try\s*\{|\.catch\(/i.test(content)) {
144
162
  findings.push({
145
163
  severity: "warning",
146
164
  category: "resilience",
@@ -150,11 +168,12 @@ export async function scanDirectory(dir) {
150
168
  });
151
169
  }
152
170
  // --- INFO: Agent without timeout ---
153
- if (/agent/i.test(content) && /async|await|fetch|request/i.test(content) && !/timeout|AbortSignal|signal/i.test(content)) {
171
+ // Only flag files with actual agent execution logic (not frontend, not configs)
172
+ if (/runAgent|agentWorkflow|executeAgent|startAgent/i.test(content) && /async|await/i.test(content) && !/timeout|AbortSignal|signal/i.test(content)) {
154
173
  findings.push({
155
174
  severity: "info",
156
175
  category: "resilience",
157
- message: "Agent operations without timeout -- could run indefinitely",
176
+ message: "Agent execution without timeout -- could run indefinitely",
158
177
  file: relPath,
159
178
  fix: "Add timeouts to agent operations to prevent runaway processes",
160
179
  });
@@ -229,6 +248,6 @@ export async function scanDirectory(dir) {
229
248
  hasDelegation,
230
249
  hasAuditLog,
231
250
  hasApprovals,
232
- scannedFiles: files.length,
251
+ scannedFiles: backendFiles.length,
233
252
  };
234
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authora/agent-audit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Security scanner for AI agents. Find vulnerabilities in your agent setup in 30 seconds.",
5
5
  "bin": {
6
6
  "agent-audit": "./dist/cli.js"
package/src/scanner.ts CHANGED
@@ -79,19 +79,36 @@ export async function scanDirectory(dir: string): Promise<ScanResult> {
79
79
 
80
80
  const files = walkDir(dir);
81
81
 
82
- for (const file of files) {
82
+ // Skip non-backend files (frontend components, tests, docs, configs)
83
+ const SKIP_PATTERNS = [
84
+ /\.(test|spec|stories)\.[tj]sx?$/,
85
+ /\/__(tests|mocks|fixtures)__\//,
86
+ /\/(web|ui|frontend|app)\/src\/(components|pages|hooks|stores|lib)\//,
87
+ /\.d\.ts$/,
88
+ /\.(md|mdx|txt|svg|css|scss|html)$/,
89
+ /package\.json$/,
90
+ /package-lock\.json$/,
91
+ /tsconfig.*\.json$/,
92
+ ];
93
+
94
+ const backendFiles = files.filter((f) => {
95
+ const rel = f.replace(dir + "/", "");
96
+ return !SKIP_PATTERNS.some((p) => p.test(rel));
97
+ });
98
+
99
+ for (const file of backendFiles) {
83
100
  const content = readFile(file);
84
101
  if (!content) continue;
85
102
  const lower = content.toLowerCase();
86
103
  const relPath = file.replace(dir + "/", "");
87
104
 
88
- // Detect agents
89
- if (/\bagent\b/i.test(content) && (/\bcreate.*agent|agent.*config|new.*agent|agent.*class\b/i.test(content))) {
105
+ // Detect agents -- only in backend code with real agent patterns
106
+ if (/\bagent\b/i.test(content) && (/\bcreateAgent|AgentConfig|new.*Agent\(|runAgent|agentWorkflow\b/i.test(content))) {
90
107
  agents++;
91
108
  }
92
109
 
93
- // Detect MCP servers
94
- if (/mcp.*server|mcpserver|model.*context.*protocol/i.test(lower)) {
110
+ // Detect MCP servers -- only files that actually create/configure MCP servers
111
+ if (/new.*Server|createServer|McpServer|startServer/i.test(content) && /mcp|model.*context.*protocol/i.test(lower)) {
95
112
  mcpServers++;
96
113
  }
97
114
 
@@ -153,29 +170,32 @@ export async function scanDirectory(dir: string): Promise<ScanResult> {
153
170
  }
154
171
 
155
172
  // --- WARNING: MCP server without auth ---
156
- if (/mcp.*server|createServer/i.test(content) && !/auth|authentication|authorization|token|apiKey/i.test(content)) {
173
+ // Only flag files that actually create/start MCP servers, not type defs or configs
174
+ if (/new.*Server|createServer|McpServer/i.test(content) && /mcp/i.test(lower) && !/auth|authentication|authorization|token|apiKey|signature/i.test(content)) {
157
175
  findings.push({
158
176
  severity: "warning",
159
177
  category: "mcp",
160
- message: "MCP server detected without visible auth configuration",
178
+ message: "MCP server created without visible auth configuration",
161
179
  file: relPath,
162
180
  fix: "Add authentication to your MCP server (API key, JWT, or Ed25519 signature verification)",
163
181
  });
164
182
  }
165
183
 
166
184
  // --- WARNING: Broad agent permissions ---
167
- if (/\*.*permission|admin.*role|full.*access|sudo|root/i.test(content) && /agent/i.test(content)) {
185
+ // Only flag if it's clearly giving an agent admin/wildcard access
186
+ if (/permissions.*\[.*["']\*["']|role.*["']admin["']|full.*access.*agent/i.test(content)) {
168
187
  findings.push({
169
188
  severity: "warning",
170
189
  category: "permissions",
171
- message: "Agent may have overly broad permissions",
190
+ message: "Agent configured with overly broad permissions",
172
191
  file: relPath,
173
192
  fix: "Apply least-privilege: give agents only the permissions they need for their specific task",
174
193
  });
175
194
  }
176
195
 
177
196
  // --- WARNING: No error handling on tool calls ---
178
- if (/tool.*call|callTool|execute.*tool/i.test(content) && !/try|catch|error/i.test(content)) {
197
+ // Only flag actual tool execution code, not type definitions or prompts
198
+ if (/callTool\(|executeTool\(|tool\.execute\(/i.test(content) && !/try\s*\{|\.catch\(/i.test(content)) {
179
199
  findings.push({
180
200
  severity: "warning",
181
201
  category: "resilience",
@@ -186,11 +206,12 @@ export async function scanDirectory(dir: string): Promise<ScanResult> {
186
206
  }
187
207
 
188
208
  // --- INFO: Agent without timeout ---
189
- if (/agent/i.test(content) && /async|await|fetch|request/i.test(content) && !/timeout|AbortSignal|signal/i.test(content)) {
209
+ // Only flag files with actual agent execution logic (not frontend, not configs)
210
+ if (/runAgent|agentWorkflow|executeAgent|startAgent/i.test(content) && /async|await/i.test(content) && !/timeout|AbortSignal|signal/i.test(content)) {
190
211
  findings.push({
191
212
  severity: "info",
192
213
  category: "resilience",
193
- message: "Agent operations without timeout -- could run indefinitely",
214
+ message: "Agent execution without timeout -- could run indefinitely",
194
215
  file: relPath,
195
216
  fix: "Add timeouts to agent operations to prevent runaway processes",
196
217
  });
@@ -271,6 +292,6 @@ export async function scanDirectory(dir: string): Promise<ScanResult> {
271
292
  hasDelegation,
272
293
  hasAuditLog,
273
294
  hasApprovals,
274
- scannedFiles: files.length,
295
+ scannedFiles: backendFiles.length,
275
296
  };
276
297
  }