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.11according 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 inselfdrive/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
pickledeserialization 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.mdfile 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()orpickle.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.11to0.11.2without 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.
Related recipes
- Source code injection sink audit
- Source code supply chain build integrity audit
- Source code secrets and data exposure audit
- SAST finding triage and fix
References
- Tenable CVE mirror: https://www.tenable.com/cve/CVE-2026-12191
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-12191
- openpilot repository: https://github.com/commaai/openpilot
- openpilot releases: https://github.com/commaai/openpilot/blob/master/RELEASES.md