🕵️♂️ 自动GitHub扫描器 - 检测暴露的AWS IAM密钥
高级
这是一个SecOps领域的自动化工作流,包含 18 个节点。主要使用 If, Code, Wait, Slack, HttpRequest 等节点。 自动GitHub扫描器 - 检测暴露的AWS IAM密钥
前置要求
- •Slack Bot Token 或 Webhook URL
- •可能需要目标 API 的认证凭证
分类
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "Tcy2xebw2oGWMxUN",
"meta": {
"instanceId": "c62c01f3e843893075a10f252ec7d6d69e5ab593af019f50055d506cb3081b99",
"templateCredsSetupCompleted": true
},
"name": "🕵️♂️ 自动 GitHub 扫描器 - 检测暴露的 AWS IAM 密钥",
"tags": [
{
"id": "XuoVybTXeUXuim6G",
"name": "✅ Live",
"createdAt": "2025-06-08T07:59:43.586Z",
"updatedAt": "2025-06-08T07:59:43.586Z"
},
{
"id": "MbPHhZHgb39Syuoa",
"name": "🔐 SecOps",
"createdAt": "2025-04-20T05:18:20.689Z",
"updatedAt": "2025-06-08T08:01:56.494Z"
}
],
"nodes": [
{
"id": "84edf6c4-fc87-4b34-86c6-ad72c15cafe8",
"name": "当点击\"执行工作流\"时",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-880,
75
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b2c1157f-c1eb-4d22-95d0-6ec166a93a4a",
"name": "拆分用户进行处理",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-220,
75
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "ae5a0e4f-892c-4a75-bdcc-36253fbc7274",
"name": "获取用户访问密钥",
"type": "n8n-nodes-base.httpRequest",
"position": [
0,
0
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "ListAccessKeys"
},
{
"name": "Version",
"value": "2010-05-08"
},
{
"name": "UserName",
"value": "={{ $json.username }}"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "0946f05d-11f0-480b-934a-c996bbb9551e",
"name": "仅筛选活动密钥",
"type": "n8n-nodes-base.if",
"position": [
220,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "active-key-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].Status }}",
"rightValue": "Active"
}
]
}
},
"typeVersion": 2
},
{
"id": "8f9db031-245e-4c00-bdb9-4ed55e9b57b2",
"name": "在 GitHub 中搜索暴露的密钥",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
0
],
"parameters": {
"url": "={{ $json.simpleSearch.searchUrl }}",
"options": {
"timeout": 10000,
"response": {
"response": {
"responseFormat": "json"
}
}
},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "githubApi"
},
"credentials": {
"githubApi": {
"id": "3fz93A0mgyxzXGOL",
"name": "GitHub account"
}
},
"typeVersion": 4.1
},
{
"id": "a6cd482c-86d2-49ac-aefe-6beec92c98af",
"name": "聚合搜索结果",
"type": "n8n-nodes-base.code",
"position": [
1100,
0
],
"parameters": {
"jsCode": "// Aggregate all search results\nconst allResults = [];\nconst accessKeyId = $input.first().json.accessKeyId;\nconst userName = $input.first().json.userName;\n\nfor (const item of $input.all()) {\n if (item.json.total_count > 0) {\n allResults.push(...item.json.items);\n }\n}\n\n// Remove duplicates based on repository and file path\nconst uniqueResults = allResults.filter((item, index, self) => \n index === self.findIndex(t => t.repository.full_name === item.repository.full_name && t.path === item.path)\n);\n\nreturn [{\n accessKeyId,\n userName,\n totalMatches: uniqueResults.length,\n repositories: uniqueResults,\n isCompromised: uniqueResults.length > 0\n}];"
},
"typeVersion": 2
},
{
"id": "75ed15ec-fdee-4644-a83c-6b47005dcac1",
"name": "检查被泄露的密钥",
"type": "n8n-nodes-base.if",
"position": [
1320,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "ebf33a67-f8f3-4700-8579-1d33b7a642d5",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "isCompromised",
"rightValue": "={{ $json.isCompromised }}"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "57753be8-33d2-4172-94a2-0d5a4f7c73ec",
"name": "生成安全报告",
"type": "n8n-nodes-base.code",
"position": [
1540,
0
],
"parameters": {
"jsCode": "// Generate comprehensive security report - Notification Only (No Automatic Actions)\nconst data = $input.item.json;\n\nconst report = {\n timestamp: new Date().toISOString(),\n accessKeyId: data.accessKeyId,\n userName: data.userName,\n status: data.isCompromised ? 'COMPROMISED' : 'SAFE',\n totalRepositories: data.totalMatches,\n repositories: data.repositories.map(repo => ({\n name: repo.repository.full_name,\n url: repo.html_url,\n path: repo.path,\n score: repo.score\n })),\n actionTaken: data.isCompromised ? 'Security team notified - Manual review required' : 'No action required',\n riskLevel: data.totalMatches > 5 ? 'HIGH' : data.totalMatches > 0 ? 'MEDIUM' : 'LOW',\n notificationSent: data.isCompromised ? true : false,\n requiresManualAction: data.isCompromised ? true : false,\n recommendedActions: data.isCompromised ? [\n 'Manually disable the compromised access key',\n 'Generate new access keys for affected services',\n 'Remove exposed keys from repositories',\n 'Audit recent API usage for this key'\n ] : []\n};\n\nreturn [report];"
},
"typeVersion": 2
},
{
"id": "f2634090-b035-4592-ad56-b970c2bff14c",
"name": "继续扫描",
"type": "n8n-nodes-base.noOp",
"position": [
2340,
80
],
"parameters": {},
"typeVersion": 1
},
{
"id": "158340f1-4dc4-4b4c-933f-95a28be524dc",
"name": "Slack",
"type": "n8n-nodes-base.slack",
"position": [
2020,
0
],
"webhookId": "47dc1fb0-71c0-40f6-8263-88880f01a436",
"parameters": {
"text": "={{ $json.message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "C08Q2H8SRUP"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "i1yhHILyYn12345678",
"name": "Slack account"
}
},
"typeVersion": 2.3
},
{
"id": "c0300832-418b-4fa8-98b6-2b799f2bcfe6",
"name": "格式化 Slack 警报",
"type": "n8n-nodes-base.code",
"position": [
1760,
0
],
"parameters": {
"jsCode": "/**\n * GitHub Scanner for Exposed AWS IAM Keys - Data Processor\n * \n * This script processes the results from the AWS IAM Key scanner workflow\n * and formats them for reporting and notification purposes.\n */\n\n// Main entry point - this is what n8n will call\n// Input: items array from n8n workflow\n// Output: Slack Block Kit UI format (blocks array only)\nconst items = $input.all();\n\n// Process the input data\nconst scanResults = items.map(item => item.json);\nconst processedResults = processIAMScanResults(scanResults);\n\n// Format for markdown notification\nconst markdownNotification = formatForMarkdownNotification(processedResults);\n// Return as array of objects for n8n\nreturn [{ message: markdownNotification }];\n\n/**\n * Process scan results and format them for reporting\n * @param {Array} scanResults - Array of scan result objects from the workflow\n * @returns {Array} Array of formatted result objects\n */\nfunction processIAMScanResults(scanResults) {\n if (!Array.isArray(scanResults) || scanResults.length === 0) {\n return [{\n status: 'NO_RESULTS',\n timestamp: new Date().toISOString(),\n message: 'No scan results to process'\n }];\n }\n\n // Process each scan result\n const processedResults = scanResults.map(result => {\n // Create a deep copy to avoid modifying the original data\n const processedResult = JSON.parse(JSON.stringify(result));\n \n // Ensure we have the required fields\n if (!processedResult.timestamp) {\n processedResult.timestamp = new Date().toISOString();\n }\n \n // Calculate risk metrics if not provided\n if (!processedResult.riskLevel) {\n processedResult.riskLevel = calculateRiskLevel(processedResult);\n }\n \n // Generate recommended actions if not provided\n if (!processedResult.recommendedActions || processedResult.recommendedActions.length === 0) {\n processedResult.recommendedActions = generateRecommendedActions(processedResult);\n }\n \n return processedResult;\n });\n\n return processedResults;\n}\n \n /**\n * Calculate risk level based on scan result data\n * @param {Object} result - Individual scan result\n * @returns {string} Risk level (HIGH, MEDIUM, LOW)\n */\n function calculateRiskLevel(result) {\n // Default to MEDIUM if we can't determine\n if (!result || !result.status) {\n return 'MEDIUM';\n }\n \n // Determine risk level based on status and other factors\n if (result.status === 'COMPROMISED') {\n // Public repositories or repositories with many contributors increase risk\n if (result.repositories && result.repositories.some(repo => {\n return repo.score >= 0.8; // High score indicates higher risk\n })) {\n return 'HIGH';\n }\n return 'MEDIUM';\n } else if (result.status === 'POTENTIAL_EXPOSURE') {\n return 'MEDIUM';\n } else {\n return 'LOW';\n }\n }\n \n /**\n * Generate recommended actions based on scan result\n * @param {Object} result - Individual scan result\n * @returns {Array} List of recommended actions\n */\n function generateRecommendedActions(result) {\n const commonActions = [\n 'Review the exposure details in the security report',\n 'Rotate affected access keys immediately'\n ];\n \n if (result.status === 'COMPROMISED') {\n return [\n ...commonActions,\n 'Disable the compromised access key',\n 'Generate new access keys for affected services',\n 'Remove exposed keys from repositories',\n 'Audit recent API usage for this key'\n ];\n } else if (result.status === 'POTENTIAL_EXPOSURE') {\n return [\n ...commonActions,\n 'Verify if the exposure is a false positive',\n 'Consider rotating keys as a precaution'\n ];\n } else {\n return [\n 'No immediate action required',\n 'Continue monitoring for potential exposures'\n ];\n }\n }\n \n /**\n * Format scan results for Slack-compatible markdown notification\n * @param {Array} processedResults - Processed scan results\n * @returns {string} Slack-compatible markdown formatted notification text\n */\n function formatForMarkdownNotification(processedResults) {\n if (!Array.isArray(processedResults) || processedResults.length === 0) {\n return `🔒 *AWS IAM Key Scan Completed*\\n\\nNo exposed AWS IAM keys were detected in this scan.`;\n }\n \n // Count compromised keys\n const compromisedCount = processedResults.filter(r => r.status === 'COMPROMISED').length;\n \n if (compromisedCount === 0) {\n return `🔒 *AWS IAM Key Scan Completed*\\n\\nNo exposed AWS IAM keys were detected in this scan.`;\n }\n \n // Create Slack-compatible notification for compromised keys\n let markdown = `⚠️ *ALERT: AWS IAM Keys Exposed*\\n\\n*${compromisedCount}* AWS IAM keys have been potentially exposed on GitHub. Immediate action required.\\n\\n`;\n \n // Add details for each compromised key\n processedResults.filter(r => r.status === 'COMPROMISED').forEach((result, index) => {\n markdown += `*Exposure ${index + 1}*\\n\\n`;\n \n // Add repository information in a cleaner format\n markdown += `*Exposure Details:*\\n`;\n result.repositories.forEach(repo => {\n markdown += `• *Repository:* ${repo.name}\\n`;\n markdown += `• *Path:* \\`${repo.path}\\`\\n`;\n markdown += `• *Risk Score:* ${repo.score.toFixed(2)}\\n\\n`;\n });\n \n // Add risk level and action taken in a compact format\n markdown += `*Risk Level:* ${result.riskLevel} | *Action Taken:* ${result.actionTaken || 'None'}\\n\\n`;\n \n // Add recommended actions with better formatting\n markdown += `*Recommended Actions:*\\n`;\n result.recommendedActions.forEach(action => {\n markdown += `• ${action}\\n`;\n });\n markdown += `\\n`;\n });\n \n return markdown;\n }\n\n \n // Export functions for use in n8n workflow\n module.exports = {\n processIAMScanResults,\n calculateRiskLevel,\n generateRecommendedActions,\n formatForMarkdownNotification\n };"
},
"typeVersion": 2
},
{
"id": "3ed685c7-27b5-4a00-840a-6f9dddff6d3f",
"name": "准备 GitHub 搜索",
"type": "n8n-nodes-base.code",
"position": [
440,
0
],
"parameters": {
"jsCode": "/**\n * Simplified GitHub Search for AWS Access Keys\n * This script generates optimized search queries for finding exposed AWS access keys on GitHub\n */\n\n/**\n * Generates a GitHub API search URL for a given AWS access key\n * @param {Object} inputData - The input data containing AWS access key information\n * @returns {Object} - Search information including URL and query\n */\nfunction generateGitHubSearchQuery(inputData) {\n try {\n // Extract access key information from input\n let accessKeyId;\n let userName;\n \n // Handle different input formats\n if (inputData && typeof inputData === 'object') {\n // Check for n8n workflow format\n if (inputData.ListAccessKeysResponse && \n inputData.ListAccessKeysResponse.ListAccessKeysResult && \n inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata && \n Array.isArray(inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata) && \n inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata.length > 0) {\n \n accessKeyId = inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].AccessKeyId;\n userName = inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].UserName;\n } \n // Direct object format\n else if (inputData.accessKeyId) {\n accessKeyId = inputData.accessKeyId;\n userName = inputData.userName || 'unknown';\n }\n }\n \n // Validate we have an access key\n if (!accessKeyId) {\n console.error('No valid AWS access key ID found in input');\n return { error: 'No valid AWS access key ID found in input' };\n }\n \n // Create the most effective search query\n // Based on testing, the exact match with quotes is most reliable\n const searchQuery = `\"${accessKeyId}\" in:file`;\n \n // Generate the GitHub API search URL\n const searchUrl = `https://api.github.com/search/code?q=${encodeURIComponent(searchQuery)}`;\n \n return {\n accessKeyId,\n userName,\n searchQuery,\n searchUrl,\n note: 'A single exact match query is typically sufficient for finding exposed AWS keys'\n };\n } catch (error) {\n console.error('Error generating GitHub search query:', error);\n return { error: `Error generating GitHub search query: ${error.message}` };\n }\n}\n\n/**\n * For more comprehensive searches, this function generates multiple search patterns\n * This is optional and can be used if the simple search doesn't yield results\n * @param {string} accessKeyId - The AWS access key ID to search for\n * @returns {Array} - Array of search queries and URLs\n */\nfunction generateComprehensiveSearch(accessKeyId) {\n if (!accessKeyId) {\n return { error: 'No access key ID provided' };\n }\n \n // Search patterns for access keys (in order of effectiveness)\n const searchQueries = [\n `\"${accessKeyId}\" in:file`, // Exact match (most effective)\n `${accessKeyId} in:file`, // Without quotes (catches more results but may have false positives)\n `AWS_ACCESS_KEY_ID=${accessKeyId} in:file`, // Environment variable format\n `aws_access_key_id: ${accessKeyId} in:file`, // YAML/config format\n `accessKeyId: ${accessKeyId} in:file` // JavaScript/JSON format\n ];\n \n return searchQueries.map(query => ({\n searchQuery: query,\n searchUrl: `https://api.github.com/search/code?q=${encodeURIComponent(query)}`\n }));\n}\n\n// For n8n integration\nfunction processForN8n() {\n try {\n // Get input data\n const inputData = $input.item.json;\n \n // Generate the simplified search (recommended approach)\n const simpleSearch = generateGitHubSearchQuery(inputData);\n \n // For backward compatibility, also generate the comprehensive search\n // if an access key was successfully extracted\n let comprehensiveSearch = [];\n if (simpleSearch.accessKeyId) {\n comprehensiveSearch = generateComprehensiveSearch(simpleSearch.accessKeyId);\n }\n \n return {\n simpleSearch,\n comprehensiveSearch,\n recommendation: 'The simple search is recommended for most cases. Only use comprehensive search if simple search yields no results.'\n };\n } catch (error) {\n console.error('Error in n8n processing:', error);\n return { error: `Error in n8n processing: ${error.message}` };\n }\n}\n\n// For standalone usage\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = {\n generateGitHubSearchQuery,\n generateComprehensiveSearch\n };\n} else {\n // For n8n execution\n return processForN8n();\n}"
},
"typeVersion": 2
},
{
"id": "e58f0cd8-13df-41eb-9a9c-99efc7eba0c4",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-900,
-680
],
"parameters": {
"width": 1120,
"height": 580,
"content": "# 🔐🕵️♂️ GitHub 扫描器 - 检测暴露的 AWS IAM 密钥 - 快速概览"
},
"typeVersion": 1
},
{
"id": "ef29b02b-f2a4-4642-a5c4-c9685b0e2c22",
"name": "速率限制等待",
"type": "n8n-nodes-base.wait",
"position": [
660,
0
],
"webhookId": "850e337e-d261-456a-86c1-1725d77f9e52",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "714724b6-9aaf-4d17-97b7-1a3fd3dcaeae",
"name": "列出 AWS 用户",
"type": "n8n-nodes-base.httpRequest",
"position": [
-660,
80
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "ListUsers"
},
{
"name": "Version",
"value": "2010-05-08"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "a1448a68-81aa-4571-8f62-617c57daa6e6",
"name": "提取 AWS 用户名",
"type": "n8n-nodes-base.code",
"position": [
-440,
75
],
"parameters": {
"jsCode": "// n8n Function node: Extract usernames from AWS ListUsersResponse\n\nconst allInputs = $input.all();\n\n// Find the ListUsersResponse input\nconst listUsersInput = allInputs.find(item => item.json.ListUsersResponse);\n\nif (!listUsersInput) {\n throw new Error('No ListUsersResponse found in input data');\n}\n\n// Extract users array from the response\nconst users = listUsersInput.json\n .ListUsersResponse\n .ListUsersResult\n .Users || [];\n\n// Extract usernames and return each as a separate item for looping\nconst usernameItems = users.map(user => ({\n json: { username: user.UserName }\n}));\n\n// Return array of individual username objects\nreturn usernameItems;"
},
"typeVersion": 2
},
{
"id": "2339c570-93a3-4c1a-ae0d-2eb9810eeee8",
"name": "禁用访问密钥",
"type": "n8n-nodes-base.httpRequest",
"disabled": true,
"position": [
1200,
-620
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "UpdateAccessKey"
},
{
"name": "AccessKeyId",
"value": "AKIAEXAMPLEACCESSKEY1"
},
{
"name": "UserName",
"value": "user@domain.com"
},
{
"name": "Status",
"value": "Inactive"
},
{
"name": "Version",
"value": "2010-05-08"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "99938eb1-580b-4a91-b7a7-83464b33053e",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
-680
],
"parameters": {
"color": 6,
"width": 1200,
"height": 580,
"content": "## 🚨 自动禁用访问密钥"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "d96b586a-4739-4ef5-84c8-c71ff9f3e1e6",
"connections": {
"Slack": {
"main": [
[
{
"node": "Continue Scanning",
"type": "main",
"index": 0
}
]
]
},
"List AWS Users1": {
"main": [
[
{
"node": "Extract AWS Usernames",
"type": "main",
"index": 0
}
]
]
},
"Rate Limit Wait": {
"main": [
[
{
"node": "Search GitHub for Exposed Keys",
"type": "main",
"index": 0
}
]
]
},
"Continue Scanning": {
"main": [
[
{
"node": "Split Users for Processing",
"type": "main",
"index": 0
}
]
]
},
"Format Slack Alert": {
"main": [
[
{
"node": "Slack",
"type": "main",
"index": 0
}
]
]
},
"Get User Access Keys": {
"main": [
[
{
"node": "Filter Active Keys Only",
"type": "main",
"index": 0
}
]
]
},
"Extract AWS Usernames": {
"main": [
[
{
"node": "Split Users for Processing",
"type": "main",
"index": 0
}
]
]
},
"Prepare Github Search": {
"main": [
[
{
"node": "Rate Limit Wait",
"type": "main",
"index": 0
}
]
]
},
"Filter Active Keys Only": {
"main": [
[
{
"node": "Prepare Github Search",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Search Results": {
"main": [
[
{
"node": "Check For Compromised Keys",
"type": "main",
"index": 0
}
]
]
},
"Generate Security Report": {
"main": [
[
{
"node": "Format Slack Alert",
"type": "main",
"index": 0
}
]
]
},
"Check For Compromised Keys": {
"main": [
[
{
"node": "Generate Security Report",
"type": "main",
"index": 0
}
]
]
},
"Split Users for Processing": {
"main": [
[],
[
{
"node": "Get User Access Keys",
"type": "main",
"index": 0
}
]
]
},
"Search GitHub for Exposed Keys": {
"main": [
[
{
"node": "Aggregate Search Results",
"type": "main",
"index": 0
}
]
]
},
"When clicking ‘Execute workflow’": {
"main": [
[
{
"node": "List AWS Users1",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 安全运维
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
自动化AWS IAM密钥泄露响应,使用Slack和Claude AI
自动化AWS IAM密钥泄露响应,使用Slack和Claude AI
Set
Code
Merge
+12
40 节点Niranjan G
人工智能
钓鱼分析_URLScan_io 和 VirusTotal_
钓鱼分析 - URLScan.io 和 VirusTotal
If
Code
Wait
+10
23 节点n8n Team
安全运维
使用AI(GPT-4o)自动化数字产品和SaaS销售
使用AI(GPT-4o)自动化数字产品和SaaS销售
If
Code
Wait
+14
34 节点Badr
销售
AI个性化多产品邮件营销
基于SMTP轮换的AI个性化多产品邮件营销(GPT-4o/o3-mini)
If
Code
Wait
+16
41 节点Badr
销售
Facebook页面评论管理机器人:回复、删除、封禁和通知
AI驱动的Facebook评论管理:自动回复、删除、封禁和通知
If
Set
Code
+18
59 节点SpaGreen Creative
社交媒体
潜在客户开发与邮件工作流
使用Google Maps、SendGrid和AI自动化B2B潜在客户开发与邮件营销
If
Set
Code
+21
141 节点Ezema Kingsley Chibuzo
潜在客户开发
工作流信息
难度等级
高级
节点数量18
分类1
节点类型9
作者
Niranjan G
@niranjanCybersecurity leader turning complex workflows into seamless, AI-driven automations.
外部链接
在 n8n.io 查看 →
分享此工作流