mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-04-06 17:43:08 +00:00
feat: add n8n_audit_instance and n8n_manage_credentials tools (v2.47.0) (#702)
Add comprehensive security auditing combining n8n's built-in POST /audit API with deep workflow scanning using 50+ regex patterns for hardcoded secrets, unauthenticated webhook detection, error handling gap analysis, data retention risk assessment, and PII detection. The audit returns a compact markdown report grouped by workflow with a Remediation Playbook showing auto-fixable items (with tool chains), items requiring review, and items requiring user action. Also adds n8n_manage_credentials tool (list/get/create/update/delete/getSchema) enabling AI agents to create credentials and assign them to nodes as part of security remediation. Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
12d7d5bdb6
commit
796c427317
@@ -77,9 +77,11 @@ export class N8nApiClient {
|
||||
// Request interceptor for logging
|
||||
this.client.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
// Redact request body for credential endpoints to prevent secret leakage
|
||||
const isSensitive = config.url?.includes('/credentials') && config.method !== 'get';
|
||||
logger.debug(`n8n API Request: ${config.method?.toUpperCase()} ${config.url}`, {
|
||||
params: config.params,
|
||||
data: config.data,
|
||||
data: isSensitive ? '[REDACTED]' : config.data,
|
||||
});
|
||||
return config;
|
||||
},
|
||||
@@ -309,6 +311,40 @@ export class N8nApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
// Audit
|
||||
async generateAudit(options?: { categories?: string[]; daysAbandonedWorkflow?: number }): Promise<any> {
|
||||
try {
|
||||
const additionalOptions: Record<string, unknown> = {};
|
||||
if (options?.categories) additionalOptions.categories = options.categories;
|
||||
if (options?.daysAbandonedWorkflow !== undefined) additionalOptions.daysAbandonedWorkflow = options.daysAbandonedWorkflow;
|
||||
|
||||
const body = Object.keys(additionalOptions).length > 0 ? { additionalOptions } : {};
|
||||
const response = await this.client.post('/audit', body);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw handleN8nApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch all workflows with pagination (for audit scanning)
|
||||
async listAllWorkflows(): Promise<Workflow[]> {
|
||||
const allWorkflows: Workflow[] = [];
|
||||
let cursor: string | undefined;
|
||||
const seenCursors = new Set<string>();
|
||||
const PAGE_SIZE = 100;
|
||||
const MAX_PAGES = 50; // Safety limit: 5000 workflows max
|
||||
|
||||
for (let page = 0; page < MAX_PAGES; page++) {
|
||||
const params: WorkflowListParams = { limit: PAGE_SIZE, cursor };
|
||||
const response = await this.listWorkflows(params);
|
||||
allWorkflows.push(...response.data);
|
||||
if (!response.nextCursor || seenCursors.has(response.nextCursor)) break;
|
||||
seenCursors.add(response.nextCursor);
|
||||
cursor = response.nextCursor;
|
||||
}
|
||||
return allWorkflows;
|
||||
}
|
||||
|
||||
// Execution Management
|
||||
async getExecution(id: string, includeData = false): Promise<Execution> {
|
||||
try {
|
||||
@@ -461,6 +497,15 @@ export class N8nApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
async getCredentialSchema(typeName: string): Promise<any> {
|
||||
try {
|
||||
const response = await this.client.get(`/credentials/schema/${typeName}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw handleN8nApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Tag Management
|
||||
/**
|
||||
* Lists tags from n8n instance.
|
||||
|
||||
Reference in New Issue
Block a user