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:
Romuald Członkowski
2026-04-04 11:27:20 +02:00
committed by GitHub
parent 12d7d5bdb6
commit 796c427317
45 changed files with 3537 additions and 77 deletions

View File

@@ -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.