# [CRIT] [GHSA / CRITICAL] CVE-2026-45625: Arcane Backend: Missing admin authorization on git repository endpoints allows non-admin users to exfiltrate stored Git credentials and tamper with GitOps confi

**Source:** GitHub Security Advisories
**Published:** 2026-05-18
**Article:** https://github.com/advisories/GHSA-7h26-hg47-p9hx

## Threat Profile

Arcane Backend: Missing admin authorization on git repository endpoints allows non-admin users to exfiltrate stored Git credentials and tamper with GitOps configs

## Summary

Arcane's huma-based REST API exposes nine endpoints under `/api/customize/git-repositories` and `/api/git-repositories/sync` for managing GitOps source repositories and their stored credentials. Eight of those endpoints (`list`, `create`, `get`, `update`, `delete`, `test`, `listBranches`, `browseFiles`) never call the `che…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-45625`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1195.002** — Compromise Software Supply Chain
- **T1078.001** — Default Accounts
- **T1212** — Exploitation for Credential Access
- **T1552.001** — Credentials In Files
- **T1041** — Exfiltration Over C2 Channel
- **T1567** — Exfiltration Over Web Service
- **T1071.001** — Application Layer Protocol: Web Protocols
- **T1485** — Data Destruction
- **T1531** — Account Access Removal
- **T1078.003** — Local Accounts

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Arcane GitOps: non-admin PUT on /api/customize/git-repositories/{id} followed by /test, /branches, or /files within 5 min (CVE-2026-45625 cr

`UC_274_2` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count, min(_time) as update_time, values(Web.url) as update_url, values(Web.src) as src_ip from datamodel=Web where Web.http_method=PUT Web.url="*/api/customize/git-repositories/*" NOT Web.url="*/api/customize/git-repositories/*/*" by Web.user, Web.url | rex field=Web.url "/api/customize/git-repositories/(?<repo_id>[^/?]+)" | rename Web.user as user | join type=inner user, repo_id [| tstats `summariesonly` count, min(_time) as sink_time, values(Web.http_method) as sink_method, values(Web.url) as sink_url from datamodel=Web where (Web.http_method=POST AND Web.url="*/api/customize/git-repositories/*/test") OR (Web.http_method=GET AND (Web.url="*/api/customize/git-repositories/*/branches" OR Web.url="*/api/customize/git-repositories/*/files")) by Web.user, Web.url | rex field=Web.url "/api/customize/git-repositories/(?<repo_id>[^/]+)/(test|branches|files)" | rename Web.user as user] | where sink_time >= update_time AND sink_time <= update_time + 300 | eval delay_sec=sink_time-update_time | table update_time, sink_time, delay_sec, user, src_ip, repo_id, update_url, sink_method, sink_url
```

### Arcane backend host outbound Git/HTTPS to non-allowlisted host on port 22/443 (CVE-2026-45625 credential sink)

`UC_274_3` · phase: **c2** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count, values(All_Traffic.dest_port) as ports, values(All_Traffic.dest) as dst, min(_time) as first_seen, max(_time) as last_seen from datamodel=Network_Traffic where All_Traffic.app="arcane" OR All_Traffic.process_name IN ("arcane", "arcane-backend", "main") OR All_Traffic.src_category="arcane_host" All_Traffic.dest_port IN (22, 443) NOT All_Traffic.dest_category IN ("github_ranges", "gitlab_ranges", "bitbucket_ranges", "internal_git") by All_Traffic.src, All_Traffic.dest, All_Traffic.dest_port, All_Traffic.process_name | `drop_dm_object_name(All_Traffic)` | where count >= 1 | sort - first_seen
```

**Defender KQL:**
```kql
let LookbackHours = 24h;
let ApprovedGitHosts = dynamic(["github.com","api.github.com","codeload.github.com","gitlab.com","bitbucket.org","dev.azure.com","ssh.dev.azure.com","vs-ssh.visualstudio.com"]);
let ApprovedGitCIDRs = dynamic(["140.82.112.0/20","143.55.64.0/20","192.30.252.0/22","185.199.108.0/22"]);
let ArcaneHosts = dynamic(["arcane","arcane-backend"]); // replace with actual hostnames or device-group lookup
DeviceNetworkEvents
| where Timestamp > ago(LookbackHours)
| where DeviceName has_any (ArcaneHosts) or InitiatingProcessFileName has_any ("arcane","arcane-backend","main","git","ssh")
| where RemotePort in (22, 443)
| where RemoteIPType == "Public"
| where not(RemoteUrl has_any (ApprovedGitHosts))
| where not(ipv4_is_in_any_range(RemoteIP, ApprovedGitCIDRs))
| summarize FirstSeen=min(Timestamp), LastSeen=max(Timestamp), Hits=count(), Ports=make_set(RemotePort), Cmds=make_set(InitiatingProcessCommandLine, 8)
          by DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl
| order by FirstSeen desc
```

### Arcane GitOps: DELETE /api/customize/git-repositories/{id} by non-admin principal (CVE-2026-45625 DoS / post-exfiltration cleanup)

`UC_274_4` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count, values(Web.url) as urls, values(Web.src) as src_ips, min(_time) as first_seen, max(_time) as last_seen from datamodel=Web where Web.http_method=DELETE Web.url="*/api/customize/git-repositories/*" by Web.user, Web.http_method | rename Web.user as user | `drop_dm_object_name(Web)` | eval window_sec=last_seen-first_seen | where count >= 1 | sort - last_seen
```

### Trusted vendor binary / installer launching unusual children

`UC_SUPPLY_CHAIN` · phase: **exploit** · confidence: **Medium**

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime
    from datamodel=Endpoint.Processes
    where Processes.parent_process_name IN ("setup.exe","installer.exe","update.exe")
      AND Processes.process_name IN ("powershell.exe","cmd.exe","rundll32.exe","regsvr32.exe","mshta.exe","wscript.exe","cscript.exe","wmic.exe","bitsadmin.exe")
    by Processes.dest, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process
| `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where AccountName !endswith "$"
| where InitiatingProcessFileName in~ ("setup.exe","installer.exe","update.exe")
| where FileName in~ ("powershell.exe","cmd.exe","rundll32.exe","regsvr32.exe","mshta.exe","wscript.exe","cscript.exe","wmic.exe","bitsadmin.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-45625`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 5 use case(s) fired, 11 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
