Skip to content

fix: discover hidden executorch pickle members - #1547

Merged
mldangelo-oai merged 8 commits into
mainfrom
mdangelo/codex/fix-executorch-zip-pickle-routing
Jun 9, 2026
Merged

mldangelo-oai merged 8 commits into
mainfrom
mdangelo/codex/fix-executorch-zip-pickle-routing

Conversation

@mldangelo-oai

@mldangelo-oai mldangelo-oai commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • discover extensionless and protocol-less pickle payloads inside ExecuTorch ZIP archives
  • validate bounded structure before selecting hidden pickle candidates
  • fail closed on discovery or member-coverage gaps without caching inconclusive results
  • continue scanning later members while bounding archive work and retained diagnostics
  • preserve repeated protocol-0 GLOBAL comment-token evasions for embedded pickle analysis

Critical review findings addressed

  • reused the shared forward-compatible protocol 1-6 header guard
  • normalized protocol 6 only for bounded structural validation
  • preserved protocol-0 detection with one or more exact #\n tokens adjacent to parsed GLOBAL opcodes
  • bounded total removed comment tokens and fails closed when that budget is exceeded
  • preserved BININT2 as a valid protocol-1 starter with malicious-positive and benign-negative regressions
  • covered routed success, exit-code 2, and zero-cache fail-closed semantics
  • merged current main's ZIP snapshot, archive-budget, and raw-payload hardening

The final review found an additional false negative on the prior head: two consecutive #\n tokens caused an extensionless malicious protocol-0 payload to be omitted, while the same bytes produced five findings when passed directly to PickleScanner. The current revision detects that payload, keeps repeated-token text near-matches unselected, and refuses inconclusively after 64 comment tokens.

Validation

  • PROMPTFOO_DISABLE_TELEMETRY=1 uv run --frozen pytest -q tests/scanners/test_executorch_scanner.py tests/test_cve_2025_10155_bin_pickle.py (125 passed)
  • focused repeated-comment positive, negative, and token-budget cases (5 passed)
  • scoped Ruff check and format on the associated Python files (clean)
  • scoped mypy on the associated Python files (clean)
  • git diff --check (clean)
  • no full repository test suite run, per review instructions

Published revision

  • head: 9e3330cad03288a046aee9264c59cd6d682f6e9d
  • exact tree: 1acb9886f5e9eb5a1751ebae8ce7b954d860f911
  • synced with main at 423913409542aa6e4c3fc5eccffb2d6b1cb1f218

Review state

  • all five inline review threads are resolved
  • prior top-level review findings are represented by regressions on the published head

@github-actions

github-actions Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Workflow run and artifacts

Performance Benchmarks

Compared 12 shared benchmarks with a regression threshold of 15%.
Status: 0 regressions, 0 improved, 12 stable, 0 new, 0 missing.
Aggregate shared-benchmark median: 1.342s -> 1.339s (-0.2%).

Workload Benchmark Target Size Files Baseline Current Change Status
padded-multi-stream-upload tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_padded_multi_stream_upload multi_stream_padded 4.1 KiB 1 601.2us 576.4us -4.1% stable
nested-payload-review tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_nested_payload_review[nested_base64] nested_base64 98 B 1 543.0us 523.6us -3.6% stable
single-checkpoint-preflight tests/benchmarks/test_scan_benchmarks.py::test_scan_single_checkpoint_before_load single_checkpoint.pkl 183.0 KiB 1 67.49ms 66.68ms -1.2% stable
chunked-upload-stream tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_chunked_upload_stream chunked_stream 278.2 KiB 1 109.31ms 110.33ms +0.9% stable
direct-malicious-upload tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_direct_malicious_upload malicious_reduce 52 B 1 505.1us 500.4us -0.9% stable
suspicious-pickle-intake tests/benchmarks/test_scan_benchmarks.py::test_scan_suspicious_pickle_intake suspicious-intake 183.8 KiB 4 118.04ms 117.20ms -0.7% stable
mixed-model-repository tests/benchmarks/test_scan_benchmarks.py::test_scan_release_candidate_repository release-candidate 547.3 KiB 32 470.88ms 468.08ms -0.6% stable
nested-payload-review tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_nested_payload_review[nested_hex] nested_hex 130 B 1 529.7us 532.5us +0.5% stable
nested-payload-review tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_nested_payload_review[nested_raw] nested_raw 78 B 1 520.3us 522.1us +0.3% stable
warm-cache-rescan tests/benchmarks/test_scan_benchmarks.py::test_scan_warm_cached_repository_rescan release-candidate 547.3 KiB 32 99.55ms 99.88ms +0.3% stable
clean-training-checkpoint tests/benchmarks/test_picklescan_benchmarks.py::test_picklescan_clean_training_checkpoint safe_large 278.2 KiB 1 106.83ms 107.05ms +0.2% stable
duplicate-heavy-registry tests/benchmarks/test_scan_benchmarks.py::test_scan_duplicate_registry_snapshot registry-snapshot 915.2 KiB 13 366.72ms 367.00ms +0.1% stable

@mldangelo-oai
mldangelo-oai marked this pull request as ready for review June 8, 2026 20:29

Copy link
Copy Markdown
Contributor Author

Critical review complete and fixes published at f5249a976664be46b9634ab82886e2d219330dd5. Addressed large-operand and protocol-less false negatives, complete near-match false positives, aggregate probe-budget fail-open behavior, unreadable-member short-circuiting, and unbounded diagnostics. Focused validation: 44 ExecuTorch scanner tests passed; targeted Ruff, format check, and mypy are clean. No review threads were present. Marked ready for review; moving on without waiting for CI.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5249a9766

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread modelaudit/scanners/executorch_scanner.py Outdated
Comment thread modelaudit/scanners/executorch_scanner.py
Comment thread tests/scanners/test_executorch_scanner.py

Copy link
Copy Markdown
Contributor Author

I addressed all three review findings locally in commit bc48cc14 and merged current main cleanly. The patch is limited to modelaudit/scanners/executorch_scanner.py and tests/scanners/test_executorch_scanner.py.

Validation on the integrated head:

  • PROMPTFOO_DISABLE_TELEMETRY=1 .venv/bin/pytest -q tests/scanners/test_executorch_scanner.py -> 49 passed
  • targeted Ruff check and format check -> clean
  • targeted mypy -> clean
  • diff check -> clean

Shell push is blocked by an invalid repository credential in this environment.

@codex please address the three unresolved review threads using the resolutions described in my thread replies, preserve the malicious-positive and benign-negative regressions, add the routed exit-code/cache regression, merge current main, and push the PR branch.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5249a9766

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread modelaudit/utils/file/detection.py
Comment thread modelaudit/scanners/executorch_scanner.py Outdated
@mldangelo-oai
mldangelo-oai marked this pull request as draft June 9, 2026 08:18
@mldangelo-oai
mldangelo-oai marked this pull request as ready for review June 9, 2026 09:24

Copy link
Copy Markdown
Contributor Author

@codex review

All five prior review threads are resolved on 9628f8c93c1a25eb2a2ef2b787170b65111f8e46; the focused ExecuTorch suite passes 104 tests.

@mldangelo-oai
mldangelo-oai enabled auto-merge (squash) June 9, 2026 09:25
@mldangelo-oai
mldangelo-oai requested a review from ianw-oai June 9, 2026 09:25
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@mldangelo-oai
mldangelo-oai marked this pull request as draft June 9, 2026 10:25
auto-merge was automatically disabled June 9, 2026 10:25

Pull request was converted to draft

@mldangelo-oai
mldangelo-oai marked this pull request as ready for review June 9, 2026 11:09
@mldangelo-oai
mldangelo-oai merged commit 1f2059f into main Jun 9, 2026
22 of 27 checks passed
@mldangelo-oai
mldangelo-oai deleted the mdangelo/codex/fix-executorch-zip-pickle-routing branch June 9, 2026 11:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e3330cad0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

candidate = sample
removed_token_count = 0

while (token_index := candidate.find(b"#\n")) > 0:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip data tokens before GLOBAL comment stripping

When a hidden protocol-1 member contains an earlier binary string payload with the bytes #\n before the malicious GLOBAL ... #\n ... REDUCE sequence, this find stops on the data bytes first; parsing the truncated BINSTRING fails and _without_global_comment_tokens() returns None. The member then fails discovery and never reaches PickleScanner, so the existing comment-token evasion can still bypass hidden-member scanning by prepending a harmless BINSTRING containing #\n.

Useful? React with 👍 / 👎.

Comment on lines +611 to +612

if last_opcode_name != "GLOBAL":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle INST comment-token hidden pickles

Hidden protocol-0 payloads can use the same inserted #\n token after an INST opcode instead of GLOBAL; this branch only strips the token when the preceding opcode is GLOBAL, so a stream like (S'cmd'\ntiposix\nsystem\n#\n. is rejected during discovery and never reaches PickleScanner. Since INST carries the same module/name execution target, this leaves another extensionless ExecuTorch pickle evasion path.

Useful? React with 👍 / 👎.

Comment on lines +649 to +657
has_binary_protocol = _looks_like_binary_pickle_protocol(data_start)
has_protocolless_binary_start = data_start[0] in _PICKLE_PROTOCOLLESS_BINARY_START_BYTES
has_proto0_or_1_start = data_start[0] in PROTO0_1_START_BYTES
if not (
incomplete_protocol_prefix
or has_binary_protocol
or has_protocolless_binary_start
or has_proto0_or_1_start
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept PROTO opcode with protocol 0

A valid pickle can start with the PROTO opcode carrying protocol 0 (\x80\x00...), but this hidden-member gate only treats \x80 as a pickle when _looks_like_binary_pickle_protocol() accepts the following byte, which starts at protocol 1. An extensionless ExecuTorch ZIP member using \x80\x00 before a dangerous GLOBAL/REDUCE stream is therefore omitted from pickle_files and never scanned, even though the same payload would be analyzed if the member were named .pkl.

Useful? React with 👍 / 👎.

@github-actions github-actions Bot mentioned this pull request Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant