---
analysis: A single rule on the unprivileged bind or the file read is too noisy. This
  hunt connects the vulnerable state, the crypto setup, the splice-induced read, and
  the root escalation into a correlated sequence an analyst can trust.
blind_spots:
- id: missing-kernel-telemetry
  question: Does the host have an unpatched kernel?
  requires: accurate kernel version reporting in hb_software_inventory
  risk: If the inventory is stale or missing the linux-image package, the agent cannot
    confirm if the environment is vulnerable.
  stage: vulnerability-discovery
- id: no-syscall-telemetry
  question: Did the process use splice() specifically?
  requires: hb_file_activity with activity_id 2 (Read)
  risk: We infer splice() from the unusual unprivileged read of an executable. If
    the process reads the file normally but doesn't splice it, we may generate false
    positives.
  stage: page-cache-corruption-via-splice
coverage:
- stage: vulnerability-discovery
  status: covered
  steps:
  - find-vulnerable-hosts
  - kernel-inventory
- stage: unprivileged-crypto-socket-setup
  status: covered
  steps:
  - crypto-socket-setup
- stage: page-cache-corruption-via-splice
  status: covered
  steps:
  - sensitive-file-reads
- stage: escalated-root-execution
  status: covered
  steps:
  - escalated-root-processes
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: promote-to-detection
  justification: CVE-2026-31431 is a confirmed in-the-wild exploit (CISA KEV) that
    bypasses file-on-disk integrity monitors. A negative result confirms that memory-only
    corruption is not currently active on critical nodes.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An unprivileged local attacker exploits CVE-2026-31431 by splicing AF_ALG
  crypto sockets into the page cache of sensitive system files to achieve root execution
  without modifying files on disk.
labels:
- hunt
- attack.t1190
- attack.t1068
name: Local Privilege Escalation via Copy-Fail Page Cache Corruption
parameters:
  exclude_processes:
    default:
    - backup-agent
    - vulnerability-scanner
    - aide
    - tripwire
    - rkhunter
    description: Known legitimate readers of system binaries to exclude.
    type: list[string]
  lookback_days:
    default: '14'
    description: Days of history to examine.
    type: number
  scope_hosts:
    default: []
    description: Specific hostnames to scope the behavioral queries; leave empty for
      whole estate.
    type: list[host]
  system_binaries:
    default:
    - /usr/bin/su
    - /usr/bin/sudo
    - /etc/pam.d/sshd
    - /etc/pam.d/common-auth
    - /etc/passwd
    description: Sensitive binaries and configs targeted for page cache corruption.
    type: list[path]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://securitylabs.datadoghq.com/articles/cve-2026-31431-copy-fail-exploit-detection-with-agents/
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Start with internet-facing Linux hosts and container nodes. Focus on hosts
  where scanners have reported CVE-2026-31431, but expand to all hosts running kernel
  4.14 - 6.19.
references:
- name: Security Labs Datadog - CVE-2026-31431 Copy-Fail
  url: https://securitylabs.datadoghq.com/articles/cve-2026-31431-copy-fail-exploit-detection-with-agents/
related:
- hunt: container-escape-unprivileged
  reason: Copy-Fail can also be used for container escapes if the host page cache
    is shared.
  relation: alternative
scenario:
  stages:
  - name: Kernel Vulnerability Identification
    observables:
    - CVE-2026-31431
    - Kernel versions 4.14 through 6.19
    - CISA KEV catalog entry
    slug: vulnerability-discovery
    tactic: initial-access
    techniques:
    - T1190
  - name: Unprivileged AF_ALG Socket Configuration
    observables:
    - socket.socket(socket.AF_ALG, ...)
    - bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
    - setsockopt level 279 (SOL_ALG)
    - process.euid != 0
    slug: unprivileged-crypto-socket-setup
    tactic: execution
    techniques:
    - T1190
  - name: Page Cache Corruption via Splice
    observables:
    - os.splice() calls involving AF_ALG operation socket
    - os.open("/usr/bin/su", os.O_RDONLY)
    - open.file.path in ["/etc/pam.d/*", "/etc/security/*", "/etc/passwd"]
    - splice.file.mode & S_ISUID > 0
    slug: page-cache-corruption-via-splice
    tactic: privilege-escalation
    techniques:
    - T1068
  - name: Escalated Root Execution
    observables:
    - process.euid == 0
    - Execution of tampered /usr/bin/su
    - Bypassed PAM authentication
    slug: escalated-root-execution
    tactic: privilege-escalation
    techniques:
    - T1068
  summary: An unprivileged local user exploits a Linux kernel vulnerability (CVE-2026-31431)
    by utilizing the AF_ALG crypto socket interface and the splice() syscall to corrupt
    the page cache of sensitive system files. This allows for persistent, in-memory
    modification of binaries like /usr/bin/su or configuration files like /etc/pam.d/
    to achieve privilege escalation to root without modifying files on disk.
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
tlp: clear
type: investigation
---


# Local Privilege Escalation via Copy-Fail Page Cache Corruption

The 'Copy-Fail' exploit targets a vulnerability in the Linux kernel crypto subsystem. The adversary uses unprivileged AF_ALG sockets and the splice syscall to overwrite memory pages in the kernel page cache. Because this corruption happens in memory rather than on disk, traditional file-integrity monitoring tools and audit logs remain silent as the on-disk inode metadata never changes. This hunt identifies the specific sequence of syscalls and behavioral indicators that precede the escalation. The hunt first scopes the estate to hosts with known kernel vulnerabilities, then searches for unprivileged processes configuring crypto sockets. It then pivots to find evidence of those same processes reading sensitive binaries like /usr/bin/su or PAM configurations—a prerequisite for the memory-only overwrite. Finally, an agent weighs the full chain, including subsequent root execution of fileless or unmapped processes, to confirm exploitation.

## find-vulnerable-hosts
<!-- Identify vulnerable kernel findings -->
Scope the hunt to hosts where vulnerability scanners have already flagged CVE-2026-31431.

```sqlite target=endpoint role=scoping
~~~yaml
expected: A list of device UIDs with the specific CVE finding. Silence means the scanner
  has not detected the flaw, not that the kernel is safe.
reads:
- device_uid
- cve_uid
- severity
- status
- first_seen
silence: not_evidence_of_absence
source: hb_vulnerability_finding
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_uid, cve_uid, severity, status, first_seen FROM hb_vulnerability_finding WHERE cve_uid = 'CVE-2026-31431' AND status != 'suppressed'
```

## parallel-early-behavior
<!-- Check for early exploit preparation -->
parallel:
- → crypto-socket-setup
- → kernel-inventory
join: → early-stage-triage

## crypto-socket-setup
<!-- Unprivileged AF_ALG socket setup -->
Find non-root processes referencing the kernel crypto algorithms used by the Copy-Fail exploit.

```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: Standard users interacting with the crypto subsystem. This is the first
  behavioral marker of the exploit.
reads:
- device_hostname
- user_name
- process_name
- process_cmd_line
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, user_name, process_name, process_cmd_line, time FROM hb_process_activity WHERE (LOWER(process_cmd_line) LIKE '%af_alg%' OR LOWER(process_cmd_line) LIKE '%authencesn%') AND user_name != 'root' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## kernel-inventory
<!-- Fleet-wide kernel version inventory -->
Stack-count kernel versions to identify hosts in the vulnerable range (4.14 - 6.19).

```sqlite target=endpoint role=baseline params=(scope_hosts=scope_hosts)
~~~yaml
baseline:
  compare: first_seen
  window: 30d
expected: A list of kernel versions across the estate. Rare versions on systems showing
  crypto activity are higher priority.
prevalence:
  by: device_hostname
  key:
  - package_version
  rare_below: 5
reads:
- package_name
- package_version
- device_hostname
- collected_at
silence: evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT package_version, COUNT(DISTINCT device_hostname) AS host_count, MIN(collected_at) AS first_seen FROM hb_software_inventory WHERE (LOWER(package_name) LIKE '%linux-image%' OR LOWER(package_name) = 'kernel') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) GROUP BY package_version
```

## early-stage-triage
<!-- Assess exploit preparation -->
```agent target=hunter
cite: required
context:
- find-vulnerable-hosts
- crypto-socket-setup
- kernel-inventory
max_iterations: 4
objective: Identify suspicious AF_ALG socket configurations on hosts with kernel versions
  between 4.14 and 6.19.
success_criteria: A list of hosts and PIDs with confirmed exploit preparation behaviors.
tools:
- endpoint
```

## parallel-follow-on
<!-- Hunt for corruption and escalation -->
parallel:
- → sensitive-file-reads
- → escalated-root-processes
join: → final-chain-analysis

## sensitive-file-reads
<!-- Unprivileged reads of execution-only files -->
Identify standard users reading sensitive binaries or configurations, which Copy-Fail does via splice to corrupt memory.

```sqlite target=endpoint role=enrichment params=(lookback_days=lookback_days, scope_hosts=scope_hosts, system_binaries=system_binaries, exclude_processes=exclude_processes)
~~~yaml
expected: Read-only access to su, sudo, or PAM files by unprivileged users. Legitimate
  scanners are excluded to minimize noise.
reads:
- device_hostname
- actor_user_name
- process_name
- file_path
- time
silence: not_evidence_of_absence
source: hb_file_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, actor_user_name, process_name, file_path, time FROM hb_file_activity WHERE activity_id = 2 AND (instr(',' || '{{system_binaries}}' || ',', ',' || file_path || ',') > 0) AND actor_user_name != 'root' AND NOT (instr(',' || '{{exclude_processes}}' || ',', ',' || LOWER(process_name) || ',') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## escalated-root-processes
<!-- Escalated root execution and fileless code -->
Find root processes that were likely launched after successful memory corruption, focusing on those with no disk backing.

```sqlite target=endpoint role=triage params=(lookback_days=lookback_days, scope_hosts=scope_hosts)
~~~yaml
expected: New root processes running from memory or temporary paths. This confirms
  the exploit achieved its objective.
reads:
- device_hostname
- user_name
- process_name
- process_path
- process_cmd_line
- on_disk
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, user_name, process_name, process_path, process_cmd_line, on_disk, time FROM hb_process_activity WHERE user_name = 'root' AND (on_disk = 0 OR process_path IS NULL OR LOWER(process_path) LIKE '/tmp/%' OR LOWER(process_path) LIKE '/dev/shm/%') AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## final-chain-analysis
<!-- Verify full exploit chain -->
```agent target=hunter
cite: required
context:
- early-stage-triage
- sensitive-file-reads
- escalated-root-processes
max_iterations: 5
objective: 'Confirm if any host shows the sequence: vulnerable kernel + unprivileged
  AF_ALG bind + unprivileged system binary read + root execution.'
success_criteria: "A verdict of 'compromised' for any host with correlated prepara\xE7\
  \xE3o and escalation telemetry."
tools:
- endpoint
```

## route-on-verdict
<!-- Route on exploit verdict -->
if~: "The final-chain-analysis verdict is 'compromised' for any host." (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: missing-kernel-telemetry)
else: → analyst-review

## isolate-host
<!-- Isolate compromised host -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host immediately. Because this exploit corrupts memory pages, collect a memory dump before rebooting if possible, but prioritize network containment.
```
→ analyst-review

## analyst-review
<!-- Final analyst review -->
```manual target=analyst
Review the correlated timeline in final-chain-analysis. Specifically, confirm if the root shell (on_disk=0) appeared after an unprivileged user read /usr/bin/su. If no vulnerability findings existed for the host, verify the kernel version manually.
```
→ close-out

## close-out
<!-- Document results and remediation -->
```manual target=analyst
Document every host found with a vulnerable kernel. Prioritize applying AppArmor or SELinux profiles to restrict AF_ALG socket creation for unprivileged users across the estate.
```
→ end
