{
  "id": "B8b52ViroIFRPWW9",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Simple Log Anomaly Detector with Slack",
  "tags": [],
  "nodes": [
    {
      "id": "f094a345-e855-4b5d-ac8d-632391f46122",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -224,
        224
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 1
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7f5f4655-952a-4831-aa3c-b11cda85f9bc",
      "name": "Fetch Logs",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        0,
        224
      ],
      "parameters": {
        "url": "https://api.yourlogserver.com/logs/recent?limit=100",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "faeaf2cb-3cc0-48a2-be1c-48348303eeb6",
      "name": "Count Failed Logins",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        224
      ],
      "parameters": {
        "jsCode": "const failedLogins = $json.data.filter(log => log.event === 'login_failure');\nconst uniqueIps = [...new Set(failedLogins.map(log => log.ip))];\nconst loginFailureCount = failedLogins.length;\n\nreturn [{\n    json: {\n        loginFailureCount,\n        uniqueIps,\n        firstFailedAttemptTime: failedLogins[0]?.timestamp,\n        lastFailedAttemptTime: failedLogins[loginFailureCount - 1]?.timestamp,\n        summary: `Detected ${loginFailureCount} failed login attempts from ${uniqueIps.length} unique IP(s): ${uniqueIps.join(', ')}`\n    }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "32686dc4-17d9-4d71-adb8-684558a43e7d",
      "name": "Failed Logins > Threshold?",
      "type": "n8n-nodes-base.if",
      "position": [
        448,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "af403d1c-04f9-4b8a-9575-f39b7c14aa2a",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.loginFailureCount }}",
              "rightValue": 5
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7277f88b-4510-4e40-a41d-1ecf1cff44f1",
      "name": "Send Anomaly Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        672,
        144
      ],
      "parameters": {
        "text": "=\ud83d\udea8 *SECURITY ALERT: High Volume of Failed Logins Detected!* \ud83d\udea8\\nSummary: *{{ $json.summary }}*\\nFirst attempt: *{{ $json.firstFailedAttemptTime }}*\\nLast attempt: *{{ $json.lastFailedAttemptTime }}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "yourid12"
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ca2fdc19-9814-4b1e-8534-a4919c3a7cc3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        112
      ],
      "parameters": {
        "color": 3,
        "width": 1232,
        "height": 304,
        "content": "## Flow"
      },
      "typeVersion": 1
    },
    {
      "id": "85d53433-3994-4893-8f6b-680face132b0",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        464
      ],
      "parameters": {
        "color": 5,
        "width": 1232,
        "height": 1264,
        "content": "# \ud83d\udd75\ufe0f Simple Log Anomaly Detector \ud83e\udde0\n\n* **Problem Solved:**\n    Detecting cyberattacks like brute-force or unauthorized login attempts early is crucial. However, the manual process of sifting through system logs to find suspicious patterns\u2014such as \"repeated failed logins\" or \"access from unusual locations\"\u2014is a tedious, time-consuming, and often ineffective task. These anomalous patterns can easily be missed, giving attackers a window to operate undetected.\n\n* **Solution Overview:**\n    This n8n workflow provides a powerful yet concise solution with **basic SIEM (Security Information and Event Management) functionality**. It periodically pulls logs from a specified source, processes the data, and **looks for unusual patterns, such as a high volume of failed login attempts in a short period**. If this suspicious activity exceeds a set threshold, the workflow sends a **detailed alert to Slack**. This gives your team proactive, early detection of potential threats without the burden of manual log review.\n\n* **For Whom:**\n    This automation is ideal for:\n    * **IT Teams and SysAdmins:** To monitor logs for anomalies on servers and applications.\n    * **Security Specialists:** As a simple, effective early-warning tool for common attacks.\n    * **DevOps Teams:** To track unusual activity in staging or production environments.\n    * **Any Business (especially SMEs):** That manages its own servers and needs an effective way to enhance security without a large investment in SIEM tools.\n\n### Scope\n* **What it does:**\n    * Runs on a customizable schedule (e.g., every 15 minutes).\n    * Pulls log data from a specified external source via an API endpoint.\n    * Processes the log data to filter and count specific events (e.g., login failures).\n    * Checks if the count of these events exceeds a predefined threshold.\n    * Sends a detailed alert to a Slack channel if the threshold is breached.\n* **What it doesn't do:**\n    * This workflow **does not perform a comprehensive security analysis** of all log events. It is focused on a single, user-defined pattern (e.g., failed logins).\n    * It does not automatically block malicious IPs or take any other remediation actions. It is a detection and alerting tool only.\n    * It does not store historical log data for long-term analysis.\n\n### How It Works: The 5-Node Anomaly Detection Flow\n\nThis workflow efficiently processes logs to detect anomalies.\n\n1.  **Scheduled Check (Cron Node):**\n    * **Function:** This is the primary trigger. It schedules the workflow to run at a defined interval (e.g., every 15 minutes).\n    * **Process:** The `Cron` node automatically starts the workflow on its schedule, ensuring logs are routinely scanned for suspicious activity.\n\n2.  **Fetch Logs (HTTP Request Node):**\n    * **Function:** This node is responsible for retrieving logs from an external source.\n    * **Process:** It sends a request to your log API endpoint to get a batch of the most recent logs.\n\n3.  **Count Failed Logins (Code Node):**\n    * **Function:** This is the core of the detection logic. It processes the raw log data.\n    * **Process:** The JavaScript code filters the logs for a specific event (`\"login_failure\"`), counts the total, and identifies unique IPs involved. This information is then passed to the next node.\n\n4.  **Failed Logins > Threshold? (If Node):**\n    * **Function:** This node serves as the final filter. It checks if the total count of failed logins exceeds a threshold you set (e.g., more than 5 attempts).\n    * **Process:** If the count is greater than the threshold, the workflow is routed to the notification node. If not, the workflow ends safely.\n\n5.  **Send Anomaly Alert (Slack Node):**\n    * **Function:** This node sends an alert to your team if an anomaly is detected.\n    * **Process:** The alert sent to Slack includes a summary of the anomaly, such as the number of failed attempts and the IPs involved, enabling a swift response."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "f0ceb14b-4265-4c28-83fd-7c92bf58af24",
  "connections": {
    "Fetch Logs": {
      "main": [
        [
          {
            "node": "Count Failed Logins",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Fetch Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Count Failed Logins": {
      "main": [
        [
          {
            "node": "Failed Logins > Threshold?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Failed Logins > Threshold?": {
      "main": [
        [
          {
            "node": "Send Anomaly Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}