---
analysis: This hunt uses a version-based gate to focus deep behavioral analysis and
  stack-counting only on vulnerable hosts, allowing for higher fidelity detection
  of stealthy API-based credential extraction than a simple pattern match.
blind_spots:
- id: inventory-visibility-gap
  question: Are there unmanaged GitLab instances missing an endpoint agent?
  requires: hb_software_inventory coverage for shadow IT
  risk: An unmanaged GitLab instance will not be identified as vulnerable and may
    be exploited without appearing in this hunt's results.
  stage: vulnerability-exposure-assessment
- id: http-body-blindness
  question: What specific arguments were inside the GraphQL POST requests?
  requires: HTTP POST body inspection
  risk: Malicious GraphQL subscriptions are carried in the POST body; without body
    inspection, we can only see the endpoint name and not the specific data extracted.
  stage: insecure-deserialization-credential-access
coverage:
- stage: vulnerability-exposure-assessment
  status: covered
  steps:
  - find-gitlab-versions
  - assess-vulnerability
- stage: unauthenticated-path-traversal
  status: covered
  steps:
  - detect-path-traversal
- stage: insecure-deserialization-credential-access
  status: covered
  steps:
  - rare-api-usage
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: promote-to-detection
  justification: CVE-2026-85706 is a CVSS 10.0 vulnerability actively exploited in
    the wild to steal application secrets. Confirming that all GitLab instances are
    patched is a critical control for protecting code repositories.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An adversary is exploiting unauthenticated path traversal in the GitLab
  repository commits API to read server configuration or using insecure deserialization
  in Duo Chat to extract sensitive credentials.
labels:
- hunt
- attack.t1190
- attack.t1552.004
- credential access
- initial access
name: GitLab Critical API Exploitation
parameters:
  lookback_days:
    default: '14'
    description: Days of history to examine for behavioral signals.
    from:
      kind: manual
      observed: '2026-09-14'
      ref: hunt-standard-lookback
    type: number
  scope_hosts:
    default: []
    description: Hostnames identified as running GitLab in the scoping step.
    from:
      kind: manual
      observed: '2026-09-14'
      ref: scoping-step
    type: list[host]
  sensitive_files:
    default:
    - /etc/passwd
    - gitlab.rb
    - database.yml
    description: Target files for path traversal exploitation.
    from:
      kind: article
      observed: '2026-09-14'
      ref: rapid7-gitlab-etr
    type: list[path]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://www.rapid7.com/blog/post/etr-cve-2026-85706-critical-gitlab-path-traversal-exploited-in-the-wild
    gates:
    - dry-run
    - lint
    - critic
    model: hb_google/gemini-3-flash-preview
rationale: Focus on self-managed GitLab Community and Enterprise edition servers.
  Use software inventory to establish the high-risk scope first.
references:
- name: "Rapid7 \u2014 CVE-2026-85706: Critical GitLab Path Traversal Exploited in\
    \ the Wild"
  url: https://www.rapid7.com/blog/post/etr-cve-2026-85706-critical-gitlab-path-traversal-exploited-in-the-wild
related:
- hunt: gitlab-web-shell-activity
  reason: Successful file reading often precedes the deployment of web shells.
  relation: follows
scenario:
  stages:
  - name: GitLab Vulnerability Presence
    observables:
    - GitLab Community Edition versions 18.7 to 19.1.7
    - GitLab Enterprise Edition versions 19.2 to 19.2.5
    - GitLab Enterprise Edition versions 19.3 to 19.3.1
    slug: vulnerability-exposure-assessment
    tactic: initial-access
    techniques:
    - T1190
  - name: Unauthenticated API Path Traversal
    observables:
    - HTTP requests to /api/v4/projects/:id/repository/commits
    - Path traversal sequences (../) in repository API parameters
    - Requests targeting /etc/passwd or gitlab.rb configuration files
    slug: unauthenticated-path-traversal
    tactic: initial-access
    techniques:
    - T1190
  - name: Duo Chat GraphQL Credential Access
    observables:
    - Specially crafted GraphQL subscription arguments
    - Duo Chat API interaction
    - Extraction of Advanced Search instance configurations
    - Access to sensitive GitLab credentials
    slug: insecure-deserialization-credential-access
    tactic: credential-access
    techniques:
    - T1190
    - T1552.004
  summary: Unauthenticated attackers are exploiting a critical path traversal vulnerability
    (CVE-2026-85706) in the GitLab repository commits API to read arbitrary system
    files. A secondary vulnerability (CVE-2026-87719) allows authenticated users with
    Duo Chat access to extract sensitive credentials and configurations via insecure
    deserialization in GraphQL subscriptions.
severity: high
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
  web:
    category: siem
    name: Web server / proxy logs
    telemetry:
    - network
tlp: clear
type: investigation
---


# GitLab Critical API Exploitation

The adversary attempts to exploit critical path traversal and deserialization vulnerabilities in self-managed GitLab instances to steal configuration files and credentials. This hunt targets CVE-2026-85706 and CVE-2026-87719 by first identifying exposed versions within the software inventory. If vulnerable versions are confirmed, it triggers a deep behavioral analysis of HTTP telemetry to find direct directory traversal sequences, access to sensitive files like gitlab.rb, and anomalous GraphQL API patterns associated with Duo Chat. An agent weighs the version risk against the observed traffic to confirm exploitation.

## find-gitlab-versions
<!-- Find GitLab instances and versions -->
Identify every self-managed GitLab installation in the estate and record its version to assess exposure to CVE-2026-85706.

```sqlite target=endpoint role=scoping
~~~yaml
expected: A list of hosts running GitLab with their current versions. Silence indicates
  no GitLab software is installed on agent-enrolled hosts.
reads:
- device_hostname
- package_name
- package_version
silence: not_evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-09-29'
~~~
SELECT device_hostname, package_name, package_version, vendor_name FROM hb_software_inventory WHERE (LOWER(package_name) LIKE '%gitlab%' OR LOWER(vendor_name) LIKE '%gitlab%') AND asset_scope = 'endpoint'
```

## assess-vulnerability
<!-- Assess version vulnerability -->
```agent target=hunter
cite: required
context:
- find-gitlab-versions
max_iterations: 3
objective: Determine if any host is running GitLab versions 18.7 to 19.1.7, 19.2 to
  19.2.5, or 19.3 to 19.3.1 based on the scoping query results.
success_criteria: A verdict for each host citing its version relative to the advisory.
tools:
- endpoint
- web
```

## gate-on-vulnerability
<!-- Gate: Proceed to behavioral analysis? -->
if~: "the assessment identifies at least one host running a vulnerable GitLab version" (confidence: high, judge=hunter)
then: → exploitation-fan-out
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: inventory-visibility-gap)
else: → close-out

## exploitation-fan-out
<!-- Simultaneous exploitation scan -->
parallel:
- → detect-path-traversal
- → rare-api-usage
join: → triage-exploitation

## detect-path-traversal
<!-- Detect path traversal behavior -->
Identify HTTP requests containing traversal sequences or targeting sensitive configuration files.

```sqlite target=web role=detection-candidate params=(scope_hosts=scope_hosts, sensitive_files=sensitive_files, lookback_days=lookback_days)
~~~yaml
expected: HTTP requests targeting /etc/passwd or gitlab.rb. Status 200 OK on these
  paths indicates successful file retrieval.
reads:
- url_path
- url_full
- status_code
- src_endpoint_ip
silence: not_evidence_of_absence
source: hb_http_activity
verified: dry-run
verified_at: '2026-09-29'
~~~
SELECT device_hostname, src_endpoint_ip, url_path, url_full, status_code, time FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND (instr(url_full, '../') > 0 OR instr(url_full, '..%2f') > 0 OR instr(',' || '{{sensitive_files}}' || ',', ',' || url_path || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## rare-api-usage
<!-- Identify rare API path usage -->
Use stack-counting to identify anomalous GraphQL or Duo Chat API paths that differ from standard fleet traffic.

```sqlite target=web role=baseline params=(scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: API endpoints used on only one or two hosts, highlighting potential exploitation
  of GraphQL subscriptions.
prevalence:
  by: device_hostname
  key:
  - url_path
  rare_below: 3
reads:
- url_path
silence: not_evidence_of_absence
source: hb_http_activity
verified: dry-run
verified_at: '2026-09-29'
~~~
SELECT url_path, COUNT(DISTINCT device_hostname) AS hosts, COUNT(*) AS requests, MIN(time) AS first_seen FROM hb_http_activity WHERE ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND url_path LIKE '%/api/%' AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY url_path HAVING hosts <= 2 ORDER BY hosts ASC
```

## triage-exploitation
<!-- Triage exploitation evidence -->
```agent target=hunter
cite: required
context:
- assess-vulnerability
- detect-path-traversal
- rare-api-usage
max_iterations: 6
objective: Confirm whether any vulnerable GitLab instance shows successful path traversal
  or rare API activity consistent with credential access.
success_criteria: A final verdict for every scoped host citing relevant HTTP requests.
tools:
- endpoint
- web
```

## route-on-verdict
<!-- Route on triage verdict -->
if~: "the triage verdict is malicious for at least one host due to successful path traversal or credential extraction" (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: http-body-blindness)
else: → analyst-review

## isolate-host
<!-- Isolate GitLab server -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the compromised GitLab host from the network. Revoke all credentials and rotate database secrets.
```
→ analyst-review

## analyst-review
<!-- Analyst forensic review -->
```manual target=analyst
Review the full HTTP activity for the cited hosts. Check GitLab application logs for unusual GraphQL activity. Confirm if /etc/passwd or config files were successfully read.
```
→ close-out

## close-out
<!-- Close out and remediate -->
```manual target=analyst
Record the patch status of every identified GitLab host. For those running vulnerable versions, coordinate immediate updates with the infrastructure team.
```
→ end
