CVE-2026-12191 - openpilot pickle deserialization

openpilot contains a local deserialization issue in selfdrive/modeld/modeld.py. Public CNA/NVD mirrors say the vulnerable path uses pickle.load() or pickle.loads() in openpilot 0.11, allowing a local attacker with access to the relevant model or artifact path to supply a crafted pickle payload and execute code during deserialization.

GitHub’s public RELEASES.md shows openpilot 0.11.2 was published on 2026-06-15, but no primary advisory located during this run states that the deserialization issue is fixed there. Do not assume a newer tag is sufficient unless the diff removes or hardens the pickle path.

When to use it

Use this recipe when a repository vendors openpilot, carries model-loading code, or accepts local/update-channel artifacts that can influence pickle deserialization. It is designed for source-code remediation, model artifact trust review, local writable-path audit, signed artifact enforcement, and evidence that attacker-controlled files cannot reach Python object deserialization.

Inputs

  • openpilot version or fork state, Python dependency files, model-loading paths, update channels, artifact manifests, signature/hash policy, and SBOM or generated dependency reports.
  • Source paths that call pickle.load, pickle.loads, model loaders, cache/update handlers, removable-media imports, or artifact verification.
  • Regression fixtures for benign artifacts, unsigned artifacts, tampered hashes, writable local paths, safer serialization formats, and denied pickle loads without executing payloads.
  • Boundary evidence: who can write artifacts, host filesystem permissions, update provenance, model cache ownership, logs, disclosure owner, and rollout owner.

Affected versions

  • Vulnerable: openpilot 0.11 according to current public advisories
  • Patched: no public fixed version confirmed during this run on 2026-06-16
  • Affected surface: model-loading or artifact-loading paths that deserialize pickle data from writable local storage, update channels, caches, or side-loaded assets

Indicator-of-exposure

  • The repository depends on or vendors openpilot.
  • Code references pickle.load, pickle.loads, or wrappers around model deserialization in selfdrive/modeld/modeld.py.
  • Local users, update mechanisms, removable media, caches, or writable directories can replace or influence model artifacts before load.
  • Artifact integrity is based only on file presence or path, not on immutable signatures or hashes.

Quick checks:

rg -n "pickle\\.load|pickle\\.loads|modeld|selfdrive/modeld|deserialize|load_model" .
rg -n "sha256|signature|ed25519|verify|manifest" .

Windows:

rg -n "pickle\\.load|pickle\\.loads|modeld|selfdrive/modeld|deserialize|load_model" .
rg -n "sha256|signature|ed25519|verify|manifest" .

Remediation strategy

  • Remove pickle deserialization from attacker-influenced artifact paths. Use a safer format for model metadata or a strictly verified binary format instead of arbitrary Python object graphs.
  • If migration cannot land immediately, constrain the path so only signed, immutable, vendor-produced artifacts can be loaded, and verify signatures or pinned hashes before any deserialization step.
  • Eliminate writable local paths, caches, or side-load mechanisms that let untrusted actors replace model inputs.
  • Treat “local only” as meaningful but insufficient: embedded and edge systems often have shared maintenance workflows, physical access, or update channels that make local code execution a realistic boundary.
  • Add regression tests that prove tampered artifacts fail integrity checks and never reach pickle.load() or its replacement.

The prompt

Model context: this prompt was generated by GPT 5.5 Extra High reasoning.

You are remediating CVE-2026-12191 in openpilot. The vulnerable path in
`selfdrive/modeld/modeld.py` deserializes attacker-influenced pickle data and
can execute code for a local attacker. Produce exactly one output:

- A reviewer-ready PR/change request that removes or strictly contains pickle
  deserialization, pins model artifacts to verified sources, hardens writable
  paths, and documents operator follow-up, or
- TRIAGE.md if this repository does not control an affected openpilot codebase,
  fork, or deployment.

## Rules

- Scope only CVE-2026-12191 and directly related artifact-loading paths.
- Treat model files, update manifests, logs, and signing material as sensitive.
- Do not create or run a malicious pickle payload.
- Do not claim a version-only fix without proving the deserialization path is
  removed or hardened in the controlled code.
- Do not auto-merge.

## Steps

1. Inventory every controlled copy, fork, or wrapper of `openpilot`, especially
   `selfdrive/modeld/modeld.py` and any model-loading helpers.
2. Trace every path where model artifacts or metadata are read from disk,
   caches, update channels, removable media, or user-writable storage.
3. Identify whether `pickle.load()` or `pickle.loads()` is reachable from any
   attacker-influenced path.
4. If the repository does not control the affected code or runtime, stop with
   `TRIAGE.md` listing files checked and runtime owner.
5. Replace pickle with a safer format where feasible, or gate deserialization
   behind verified signatures or pinned hashes plus immutable storage.
6. Remove or harden any writable local path that can replace artifacts before
   load.
7. Add regression tests that prove tampered artifacts fail before reaching
   deserialization.
8. Add a PR body section named `CVE-2026-12191 operator actions` covering:
   - versions reviewed;
   - whether pickle remained in the final design;
   - integrity controls added;
   - writable paths removed or constrained;
   - validation that passed.
9. Run available validation: unit tests, artifact-integrity tests, static
   analysis, and non-malicious load-path tests.
10. Use PR title:
    `fix(sec): harden openpilot model deserialization`.

## Stop conditions

- The repository does not control the affected code or runtime.
- Safe migration away from pickle needs a broader model-format decision outside
  the approved scope.
- Validation would require loading a crafted malicious pickle.

Output contract

  • A reviewer-ready PR or change request that removes or fences unsafe pickle loading, verifies model artifact provenance, adds regression coverage, and documents disclosure/operator review.
  • Or a TRIAGE.md file that lists inspected loaders/artifacts, owner, observed version, writable artifact boundary, required fix, and residual risk.
  • The output must include exact validation commands and must not execute pickle payloads, read real secrets, expose model artifacts, or mutate production update channels.

Verification - what the reviewer looks for

  • Attacker-influenced paths no longer reach pickle.load() or pickle.loads(), or are blocked by strong integrity validation before deserialization.
  • Model artifacts are pinned to trusted sources with verifiable integrity.
  • Writable caches or side-load paths cannot silently replace runtime inputs.
  • Tests prove tampered artifacts are rejected safely.

Watch for

  • Claiming the issue is fixed because the tag changed from 0.11 to 0.11.2 without reviewing the deserialization path.
  • Adding hash checks after the file is already deserialized.
  • Locking down one artifact path while leaving alternate caches or update staging directories writable.

References