{
  "hunt": {
    "meta": {
      "tlp": "clear",
      "hunt": {
        "handoff": "keep-as-periodic-hunt",
        "trigger": "intel-report",
        "methodology": "model-assisted",
        "applicability": "campaign-specific",
        "justification": "Metasploit modules for unauthenticated file reads and authenticated RCE lower the barrier for attackers to gain initial access to repository secrets or server environments; a negative result over vulnerable assets confirms no immediate active compromise."
      },
      "name": "Exploitation of Web-Facing GitLab and Langflow",
      "type": "investigation",
      "labels": [
        "hunt",
        "attack.t1190"
      ],
      "series": {
        "slug": "metasploit-wrap-up-belgian-waffles-chocolates-and-modules-frites",
        "index": 1,
        "title": "Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?",
        "total": 2
      },
      "related": [
        {
          "hunt": "ipv6-dns-takeover-coercion",
          "reason": "Lateral movement via DHCPv6 and DNS coercion is a distinct technique requiring different network and identity telemetry.",
          "relation": "out-of-scope-alternative"
        }
      ],
      "targets": {
        "web": {
          "name": "Web server / proxy logs",
          "category": "siem",
          "telemetry": [
            "network"
          ]
        },
        "hunter": {
          "name": "Hunt agent",
          "agent": true
        },
        "analyst": {
          "name": "Tier-2 analyst",
          "role": "analyst"
        },
        "endpoint": {
          "name": "Endpoint telemetry (hb_ surfaces)",
          "category": "endpoint",
          "telemetry": [
            "endpoint"
          ]
        }
      },
      "analysis": "A simple detection rule for GitLab API paths would trigger on regular administrative activity; this hunt uses prevalence to isolate rare access patterns and correlates it with known vulnerable assets and secondary process-level indicators for Langflow.",
      "coverage": [
        {
          "stage": "gitlab-unauthenticated-file-read",
          "steps": [
            "identify-vulnerable-assets",
            "gitlab-api-requests"
          ],
          "status": "covered"
        },
        {
          "stage": "langflow-authenticated-rce",
          "steps": [
            "identify-vulnerable-assets",
            "langflow-suspicious-children"
          ],
          "status": "covered"
        },
        {
          "stage": "ipv6-dns-takeover-coercion",
          "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "rdp-anomalous-interaction",
          "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
          "status": "out_of_scope"
        },
        {
          "stage": "kate-plugin-persistence",
          "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
          "status": "out_of_scope"
        }
      ],
      "scenario": {
        "stages": [
          {
            "name": "GitLab Unauthenticated Arbitrary File Read",
            "slug": "gitlab-unauthenticated-file-read",
            "tactic": "initial-access",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "CVE-2026-85706",
              "HTTP requests to GitLab repository commits APIs",
              "HTTP requests to GitLab repository files APIs",
              "Module: gather/gitlab_file_read_cve_2026_85706",
              "Affected GitLab versions 18.7 up to 19.3.2"
            ]
          },
          {
            "name": "Langflow AI Authenticated RCE",
            "slug": "langflow-authenticated-rce",
            "tactic": "execution",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "CVE-2026-18729",
              "Authenticated HTTP requests to Langflow custom components",
              "Arbitrary Python code execution via Langflow process",
              "Module: multi/http/langflow_auth_rce_cve_2026_18729",
              "Langflow versions 1.11.1 and below"
            ]
          },
          {
            "name": "IPv6 DNS Takeover Coercion",
            "slug": "ipv6-dns-takeover-coercion",
            "tactic": "credential-access",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "CVE-2026-20929",
              "Rogue DHCPv6 server activity on UDP port 547",
              "Rogue IPv6 Router Advertisements (RA)",
              "Kerberos authentication relay attempts",
              "Module: spoof/dhcp/dhcpv6_dns_takeover",
              "Module: spoof/ipv6/ipv6_ra_dns_takeover"
            ]
          },
          {
            "name": "Anomalous RDP Interaction",
            "slug": "rdp-anomalous-interaction",
            "tactic": "lateral-movement",
            "techniques": [
              "T1021.001"
            ],
            "observables": [
              "Unexpected size RDP packets and responses",
              "Anomalous Remote Interactive logons",
              "RDP connections to internal assets on port 3389"
            ]
          },
          {
            "name": "Kate Plugin Persistence",
            "slug": "kate-plugin-persistence",
            "tactic": "persistence",
            "techniques": [
              "T1190"
            ],
            "observables": [
              "Writes to Kate editor plugin directories",
              "New plugin configuration files for Kate editor",
              "Module: multi/persistence/kate_plugin"
            ]
          }
        ],
        "summary": "Recent Metasploit updates introduced exploitation modules for unauthenticated file read in GitLab (CVE-2026-85706) and authenticated RCE in Langflow AI (CVE-2026-18729). The release also features native IPv6 DNS takeover modules for Kerberos relay attacks and a new persistence mechanism targeting the Kate text editor."
      },
      "severity": "high",
      "rationale": "Start with servers identified in hb_vulnerability_finding with the target CVEs. Prioritize internet-facing GitLab instances and Langflow environments used for development or production AI workflows.",
      "guardrails": {
        "claims": "no_unsupported",
        "evidence": "citation_required",
        "telemetry": "untrusted",
        "missing_data": "not_benign"
      },
      "hypothesis": "An adversary is exploiting GitLab unauthenticated file reads or Langflow authenticated RCE to access repository secrets or execute code on the server host, starting from public-facing assets.",
      "parameters": {
        "scope_hosts": {
          "from": {
            "ref": "analyst-defined",
            "kind": "manual",
            "observed": "2026-09-25"
          },
          "type": "list[host]",
          "default": [],
          "description": "Specific hostnames to narrow the behavioral search; leave empty for fleet-wide."
        },
        "lookback_days": {
          "from": {
            "ref": "default",
            "kind": "manual",
            "observed": "2026-09-25"
          },
          "type": "number",
          "default": "14",
          "description": "Days of history to examine."
        },
        "target_shells": {
          "from": {
            "ref": "standard-tradecraft",
            "kind": "manual",
            "observed": "2026-09-25"
          },
          "type": "list[string]",
          "default": [
            "sh",
            "bash",
            "zsh",
            "cmd.exe",
            "powershell.exe",
            "pwsh.exe"
          ],
          "description": "Executables commonly used as shells for RCE persistence or command execution."
        },
        "vulnerable_cves": {
          "from": {
            "ref": "Rapid7 Metasploit Wrap Up",
            "kind": "article",
            "observed": "2026-09-25"
          },
          "type": "list[string]",
          "default": [
            "CVE-2026-85706",
            "CVE-2026-18729"
          ],
          "description": "Targeted CVE identifiers for GitLab and Langflow."
        }
      },
      "provenance": {
        "authors": [
          {
            "org": "huntbase.io",
            "name": "Huntbase hunt generation"
          }
        ],
        "generated": {
          "by": "huntbase-hunt-generation",
          "from": "https://www.rapid7.com/blog/post/pt-metasploit-wrap-up-belgian-waffles-chocolates-and-modules-frites",
          "gates": [
            "dry-run",
            "lint"
          ],
          "model": "hb_google/gemini-3-flash-preview"
        }
      },
      "references": [
        {
          "url": "https://www.rapid7.com/blog/post/pt-metasploit-wrap-up-belgian-waffles-chocolates-and-modules-frites",
          "name": "Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?"
        }
      ],
      "blind_spots": [
        {
          "id": "gitlab-https-decryption",
          "risk": "If GitLab traffic is not decrypted at a monitoring point, hb_http_activity will not show the URL path, missing the exploit attempts.",
          "stage": "gitlab-unauthenticated-file-read",
          "question": "whether file read attempts occurred over encrypted HTTPS channels",
          "requires": "TLS decryption at the proxy or application-level logging"
        },
        {
          "id": "in-memory-python-execution",
          "risk": "Sophisticated RCE may execute code without spawning a separate shell; if no child process is created, the process-based query will not trigger.",
          "stage": "langflow-authenticated-rce",
          "question": "whether Python code executed entirely within the Langflow interpreter process",
          "requires": "hb_process_activity and script telemetry"
        }
      ]
    },
    "name": "Exploitation of Web-Facing GitLab and Langflow",
    "description": "This hunt targets two critical web vulnerabilities recently integrated into Metasploit: an unauthenticated local file read in GitLab (CVE-2026-85706) and an authenticated remote code execution in Langflow (CVE-2026-18729). The hunt begins by identifying vulnerable assets using inventory and vulnerability data, then checks for signs of active exploitation in parallel: it looks for rare GitLab API access patterns that suggest automated file harvesting, and detects anomalous shell processes originating from the Langflow AI service. An agent then triages the evidence per host to decide between containment or manual forensic review."
  },
  "nodes": [
    {
      "id": "hypothesis",
      "type": "hypothesis",
      "label": "Hypothesis",
      "config": {
        "tags": [],
        "series": {
          "slug": "metasploit-wrap-up-belgian-waffles-chocolates-and-modules-frites",
          "index": 1,
          "title": "Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?",
          "total": 2
        },
        "coverage": [
          {
            "stage": "gitlab-unauthenticated-file-read",
            "steps": [
              "identify-vulnerable-assets",
              "gitlab-api-requests"
            ],
            "status": "covered"
          },
          {
            "stage": "langflow-authenticated-rce",
            "steps": [
              "identify-vulnerable-assets",
              "langflow-suspicious-children"
            ],
            "status": "covered"
          },
          {
            "stage": "ipv6-dns-takeover-coercion",
            "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "rdp-anomalous-interaction",
            "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
            "status": "out_of_scope"
          },
          {
            "stage": "kate-plugin-persistence",
            "reason": "Belongs to another part of the 'Metasploit Wrap Up: Belgian Waffles, Chocolates, and\u2026Modules-Frites?' series.",
            "status": "out_of_scope"
          }
        ],
        "rationale": "An adversary is exploiting GitLab unauthenticated file reads or Langflow authenticated RCE to access repository secrets or execute code on the server host, starting from public-facing assets.",
        "blind_spots": [
          {
            "id": "gitlab-https-decryption",
            "risk": "If GitLab traffic is not decrypted at a monitoring point, hb_http_activity will not show the URL path, missing the exploit attempts.",
            "stage": "gitlab-unauthenticated-file-read",
            "question": "whether file read attempts occurred over encrypted HTTPS channels",
            "requires": "TLS decryption at the proxy or application-level logging"
          },
          {
            "id": "in-memory-python-execution",
            "risk": "Sophisticated RCE may execute code without spawning a separate shell; if no child process is created, the process-based query will not trigger.",
            "stage": "langflow-authenticated-rce",
            "question": "whether Python code executed entirely within the Langflow interpreter process",
            "requires": "hb_process_activity and script telemetry"
          }
        ],
        "scoping_notes": "Start with servers identified in hb_vulnerability_finding with the target CVEs. Prioritize internet-facing GitLab instances and Langflow environments used for development or production AI workflows.",
        "beyond_detection": "A simple detection rule for GitLab API paths would trigger on regular administrative activity; this hunt uses prevalence to isolate rare access patterns and correlates it with known vulnerable assets and secondary process-level indicators for Langflow."
      }
    },
    {
      "id": "identify-vulnerable-assets",
      "type": "query",
      "label": "Identify vulnerable web assets",
      "config": {
        "dsl": "sqlite",
        "role": "scoping",
        "source": "endpoint",
        "content": "SELECT device_uid, resource_uid, cve_uid, severity, title FROM hb_vulnerability_finding WHERE instr(',' || '{{vulnerable_cves}}' || ',', ',' || cve_uid || ',') > 0",
        "surface": "hb_vulnerability_finding",
        "description": "Locate hosts with reported vulnerabilities corresponding to the Metasploit module release to prioritize the behavioral search.",
        "expected_signal": "A list of device identifiers or resources flagged with the target CVEs. Silence means the vulnerability scanner has not identified these risks in the estate."
      },
      "parents": [
        {
          "id": "hypothesis"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "scoping",
        "label": "Identify vulnerable web assets",
        "reads": [
          "device_uid",
          "resource_uid",
          "cve_uid",
          "severity",
          "title"
        ],
        "source": "hb_vulnerability_finding",
        "target": "endpoint",
        "content": "SELECT device_uid, resource_uid, cve_uid, severity, title FROM hb_vulnerability_finding WHERE instr(',' || '{{vulnerable_cves}}' || ',', ',' || cve_uid || ',') > 0",
        "silence": "not_evidence_of_absence",
        "expected": "A list of device identifiers or resources flagged with the target CVEs. Silence means the vulnerability scanner has not identified these risks in the estate.",
        "verified": "dry-run",
        "verified_at": "2026-09-28"
      }
    },
    {
      "id": "gitlab-api-requests",
      "type": "query",
      "label": "GitLab repository API request prevalence",
      "config": {
        "dsl": "sqlite",
        "role": "baseline",
        "source": "web",
        "content": "SELECT src_endpoint_ip, url_path, device_hostname, COUNT(*) as request_count, MIN(time) as first_seen FROM hb_http_activity WHERE (LOWER(url_path) LIKE '%/api/v4/projects/%/repository/commits%' OR LOWER(url_path) LIKE '%/api/v4/projects/%/repository/files%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY src_endpoint_ip, url_path, device_hostname",
        "surface": "hb_http_activity",
        "description": "Identify rare or unauthorized access to repository commits and files APIs that suggest an automated gather module is reading files.",
        "expected_signal": "Anomalous requests to specific API paths. Rare combinations of URL paths and source IPs indicate potential exploit attempts."
      },
      "parents": [
        {
          "id": "identify-vulnerable-assets"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "baseline",
        "label": "GitLab repository API request prevalence",
        "reads": [
          "src_endpoint_ip",
          "url_path",
          "device_hostname",
          "time"
        ],
        "source": "hb_http_activity",
        "target": "web",
        "content": "SELECT src_endpoint_ip, url_path, device_hostname, COUNT(*) as request_count, MIN(time) as first_seen FROM hb_http_activity WHERE (LOWER(url_path) LIKE '%/api/v4/projects/%/repository/commits%' OR LOWER(url_path) LIKE '%/api/v4/projects/%/repository/files%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY src_endpoint_ip, url_path, device_hostname",
        "silence": "not_evidence_of_absence",
        "baseline": {
          "window": "{{lookback_days}}d",
          "compare": "first_seen"
        },
        "expected": "Anomalous requests to specific API paths. Rare combinations of URL paths and source IPs indicate potential exploit attempts.",
        "verified": "dry-run",
        "prevalence": {
          "by": "device_hostname",
          "key": [
            "url_path"
          ],
          "rare_below": 3
        },
        "verified_at": "2026-09-28"
      }
    },
    {
      "id": "langflow-suspicious-children",
      "type": "query",
      "label": "Langflow anomalous child processes",
      "config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "source": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE LOWER(parent_process_cmd_line) LIKE '%langflow%' AND instr(',' || '{{target_shells}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "surface": "hb_process_activity",
        "description": "Detect authenticated RCE in Langflow by identifying shells or interpreters spawned by the Langflow service process.",
        "expected_signal": "Shell instances where the parent command line identifies Langflow, indicating code execution."
      },
      "parents": [
        {
          "id": "identify-vulnerable-assets"
        }
      ],
      "primitive_config": {
        "dsl": "sqlite",
        "role": "detection-candidate",
        "label": "Langflow anomalous child processes",
        "reads": [
          "device_hostname",
          "process_name",
          "process_cmd_line",
          "parent_process_name",
          "parent_process_cmd_line",
          "user_name",
          "time"
        ],
        "source": "hb_process_activity",
        "target": "endpoint",
        "content": "SELECT device_hostname, process_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE LOWER(parent_process_cmd_line) LIKE '%langflow%' AND instr(',' || '{{target_shells}}' || ',', ',' || LOWER(process_name) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')",
        "silence": "not_evidence_of_absence",
        "expected": "Shell instances where the parent command line identifies Langflow, indicating code execution.",
        "verified": "dry-run",
        "verified_at": "2026-09-28"
      }
    },
    {
      "id": "triage-verdict",
      "type": "analytic",
      "label": "Triage exploitation signals",
      "config": {
        "cite": "required",
        "tools": [
          "endpoint",
          "web"
        ],
        "context": [
          "identify-vulnerable-assets",
          "gitlab-api-requests",
          "langflow-suspicious-children"
        ],
        "objective": "Determine if any host shows evidence of active exploit attempts in network or process telemetry that correlate with identified vulnerabilities.",
        "description": "Synthesize the presence of vulnerable applications with observed HTTP and process anomalies to settle on a verdict.",
        "max_iterations": 5,
        "expected_signal": "A per-host verdict of malicious, suspicious, or benign.",
        "success_criteria": "A verdict for every scoped host citing relevant rows from HTTP or process queries."
      },
      "parents": [
        {
          "id": "gitlab-api-requests",
          "kind": "merge"
        },
        {
          "id": "langflow-suspicious-children",
          "kind": "merge"
        }
      ]
    },
    {
      "id": "route-verdict",
      "type": "checkpoint",
      "label": "Route on triage verdict",
      "config": {
        "fuzzy": true,
        "judge": "hunter",
        "question": "The triage verdict is malicious or suspicious for at least one host based on the correlation of vulnerabilities and exploit indicators.",
        "condition": "The triage verdict is malicious or suspicious for at least one host based on the correlation of vulnerabilities and exploit indicators.",
        "blind_spot": "gitlab-https-decryption",
        "confidence": "high",
        "description": "Determine whether to contain a host, task an analyst, or close the hunt based on the agent findings.",
        "checkpoint_type": "mandatory"
      },
      "parents": [
        {
          "id": "triage-verdict"
        }
      ]
    },
    {
      "id": "contain-host",
      "type": "action",
      "label": "Isolate host and revoke credentials",
      "config": {
        "target": "endpoint",
        "description": "Immediately contain the breach to prevent further data exfiltration or lateral movement.",
        "instructions": "Isolate the compromised host via the EDR console and revoke active GitLab or Langflow authentication tokens for any users identified in the triage context.",
        "action_approval": "required"
      },
      "parents": [
        {
          "id": "route-verdict",
          "branch": "on_supports"
        }
      ]
    },
    {
      "id": "analyst-review",
      "type": "task",
      "label": "Manual forensic validation",
      "config": {
        "assignee": "analyst",
        "description": "Review the telemetry to confirm the scope of the compromise and identify any data exfiltrated.",
        "instructions": "Review full HTTP logs for the identified server to confirm which repository files were accessed. For Langflow, verify if child processes made any external network connections after spawning."
      },
      "parents": [
        {
          "id": "route-verdict",
          "branch": "default"
        },
        {
          "id": "route-verdict",
          "branch": "on_unavailable"
        },
        {
          "id": "contain-host"
        }
      ]
    },
    {
      "id": "close-out",
      "type": "task",
      "label": "Hunt closure and reporting",
      "config": {
        "assignee": "analyst",
        "description": "Document the findings and ensure vulnerable systems are scheduled for patching.",
        "instructions": "Record the results of the hunt. If you found vulnerable servers without exploit indicators, ensure they are patched immediately. Record any false positives from the API prevalence query for future tuning."
      },
      "parents": [
        {
          "id": "route-verdict",
          "branch": "on_refutes"
        },
        {
          "id": "analyst-review"
        }
      ]
    }
  ]
}