← All hunts high TLP:CLEAR

Local Privilege Escalation via Copy-Fail Page Cache Corruption

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.

Based on research by Datadog Security Labs 2026-09-20 12 steps · 5 queries T1068 T1190

Brief

Why this hunt matters

The Datadog Security Labs team recently published a detailed analysis of CVE-2026-31431, a critical vulnerability they named "Copy-Fail" (https://securitylabs.datadoghq.com/articles/cve-2026-31431-copy-fail-exploit-detection-with-agents/). This local privilege escalation flaw affects the Linux kernel crypto subsystem. It allows an unprivileged user to overwrite pages in the kernel's page cache. The most critical aspect of this vulnerability is its stealth: it modifies the in-memory representation of a file without changing the file on disk. This means that a binary like /usr/bin/su can be temporarily modified in memory to grant root access, while its cryptographic hash on disk remains unchanged.

Phase 1: Scoping the Environment

The hunt starts with scoping. We focus on Linux hosts with kernel versions between 4.14 and 6.19, where the vulnerability resides. We query existing vulnerability findings to identify systems already flagged by scanners. This step is a baseline: it does not confirm exploitation but narrows the field to systems that are fundamentally at risk. We also stack-count kernel versions to find outliers or systems that have missed recent patch cycles.

Phase 2: Detecting Exploit Preparation

The adversary must first interact with the kernel crypto interface by creating AF_ALG sockets. We search process telemetry for unprivileged users referencing specific crypto algorithms like authencesn. This is the first behavioral indicator. While crypto activity can be legitimate, seeing it from an unprivileged user on a vulnerable kernel significantly raises the priority of the investigation.

Phase 3: Corruption and Escalation

The core of the exploit involves using the splice syscall to move data between the crypto socket and a sensitive file. We identify this by looking for unprivileged processes reading files they should not typically access, such as /usr/bin/su, sudo binaries, or PAM configuration files. Finally, the hunt searches for new root processes that have no backing file on disk or are running from temporary memory-backed locations like /dev/shm. This correlates the preparation, the memory-only modification, and the successful root shell into a single high-confidence chain.

Blind Spots

This hunt has two main limitations. First, we infer the use of the splice syscall by looking for unprivileged file reads of system binaries; if an adversary uses a different method to trigger the page cache load, we might miss the initial read. Second, the hunt depends on the presence of kernel version data in the software inventory. If telemetry is missing or delayed, the scoping stage will not accurately identify all vulnerable hosts in the environment.

Running the Hunt

This playbook is a hunt.md file designed for automation. You can import it into Huntbase or any compatible hunt runtime. The structure ensures that heavy file-activity queries only run after the initial scoping and crypto-socket detection. This prevents performance issues across large estates. After running the queries, an automated agent analyzes the correlated timeline to provide a final verdict before the analyst begins manual review.

Steps

  1. Identify vulnerable kernel findings

    Query · scoping

    Scope the hunt to hosts where vulnerability scanners have already flagged CVE-2026-31431.

    reads hb_vulnerability_findingsql
    SELECT device_uid, cve_uid, severity, status, first_seen FROM hb_vulnerability_finding WHERE cve_uid = 'CVE-2026-31431' AND status != 'suppressed'

    What a hit looks like. 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.

  2. Unprivileged AF_ALG socket setup

    Query · detection candidate

    Find non-root processes referencing the kernel crypto algorithms used by the Copy-Fail exploit.

    reads hb_process_activitysql
    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')

    What a hit looks like. Standard users interacting with the crypto subsystem. This is the first behavioral marker of the exploit.

  3. Fleet-wide kernel version inventory

    Query · baseline

    Stack-count kernel versions to identify hosts in the vulnerable range (4.14 - 6.19).

    reads hb_software_inventorysql
    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

    What a hit looks like. A list of kernel versions across the estate. Rare versions on systems showing crypto activity are higher priority.

  4. Assess exploit preparation

    Agent triage

    The agent reviews vulnerability findings and process telemetry to identify processes preparing for page cache corruption.

  5. Unprivileged reads of execution-only files

    Query · enrichment

    Identify standard users reading sensitive binaries or configurations, which Copy-Fail does via splice to corrupt memory.

    reads hb_file_activitysql
    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')

    What a hit looks like. Read-only access to su, sudo, or PAM files by unprivileged users. Legitimate scanners are excluded to minimize noise.

  6. Escalated root execution and fileless code

    Query · triage

    Find root processes that were likely launched after successful memory corruption, focusing on those with no disk backing.

    reads hb_process_activitysql
    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')

    What a hit looks like. New root processes running from memory or temporary paths. This confirms the exploit achieved its objective.

  7. Verify full exploit chain

    Agent triage

    The agent connects the early preparation, the splicing behavior, and the root escalation into a single narrative.

  8. Route on exploit verdict

    Decision

    Route the hunt to immediate isolation or manual analyst review.

  9. Isolate compromised host

    Response action

    Contain the threat by isolating the host where kernel exploitation was confirmed.

  10. Final analyst review

    Analyst task

    Verify the agent's reasoning and confirm the malicious nature of the detected root processes.

  11. Document results and remediation

    Analyst task

    Record the hunt results and suggest broader hardening measures.

Coverage

Scenario coverage

StageCoveredHow, or why not
Kernel Vulnerability Identification
T1190
Yes find-vulnerable-hosts, kernel-inventory
Unprivileged AF_ALG Socket Configuration
T1190
Yes crypto-socket-setup
Page Cache Corruption via Splice
T1068
Yes sensitive-file-reads
Escalated Root Execution
T1068
Yes escalated-root-processes

Blind spots

  • Needs accurate kernel version reporting in hb_software_inventory. If the inventory is stale or missing the linux-image package, the agent cannot confirm if the environment is vulnerable. It would answer Does the host have an unpatched kernel?.
  • Needs hb_file_activity with activity_id 2 (Read). 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. It would answer Did the process use splice() specifically?.

Parameters & data

Parameters

ParameterTypeDefaultWhat it is
exclude_processeslist[string]backup-agent, vulnerability-scanner, aide, tripwire, rkhunterKnown legitimate readers of system binaries to exclude.
lookback_daysnumber14Days of history to examine.
scope_hostslist[host]Specific hostnames to scope the behavioral queries; leave empty for whole estate.
system_binarieslist[path]/usr/bin/su, /usr/bin/sudo, /etc/pam.d/sshd, /etc/pam.d/common-auth, /etc/passwdSensitive binaries and configs targeted for page cache corruption.

Telemetry

SourceCategoryTelemetry
Endpoint telemetry (hb_ surfaces)endpointendpoint

Source

Download hunt.md Definition (JSON) An open hunt.md file; it runs anywhere that reads the format.
---
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

Run it

Take this hunt into your environment.

Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.

Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.