Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/attestation-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The rows that run depend on the format and on the inputs: every report carries s
| Chat template | Code reach, hidden or obfuscated text, override or content-triggered instructions, and the text the rendered template adds to the prompt | `[result]` | `[evidence]` | `[notes]` |
| Tokenizer config | Tampered tokenizer tables: special-token ids, token types, control tokens | `[result]` | `[evidence]` | `[notes]` |
| Quant match (GGUF) | Declared quantization (file name) against the tensor types in the file | `[result]` | `[evidence]` | `[notes]` |
| Remote code (model directory) | Python a loader would import: modules a config names (auto_map, custom_pipelines, sentence-transformers and diffusers modules), files loaders import by their path, and the repository files those import | `[result]` | `[evidence]` | `[notes]` |
| Remote code (model directory) | Python a loader would import: modules a config names (auto_map, custom_pipelines, sentence-transformers and diffusers modules), files loaders import by their path, the repository files those import, and config.json fields that run code without trust_remote_code (a Hub kernel as the attention implementation, trust_remote_code itself) | `[result]` | `[evidence]` | `[notes]` |
| Pickle opcode scan (pickle) | Imports in pickle-based model files that reach code execution, and pickles that build more than tensors and plain containers | `[result]` | `[evidence]` | `[notes]` |
| License policy (with a policy) | The license the artifact states, against the operator's allowed list | `[result]` | `[evidence]` | `[notes, with the license's usage-policy obligations listed and not marked met]` |
| Intake policy (with a policy) | The artifact against the organization's intake policy: allowed formats, publisher allow and deny lists, and publishers whose models need a verified signature | `[result]` | `[evidence: the rule each finding breaks]` | `[notes: the policy by name and hash, the publisher and where it was read, and each rule that broke, could not be evaluated, or held]` |
Expand Down
1 change: 1 addition & 0 deletions docs/check-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ own suite, suite version, and probe-set digest ([tier2.md](tier2.md)).

| Version | Rule fingerprint | Date | Changes |
|---|---|---|---|
| `tier1/0.12` | `00b784144756ac03404c549c0bc2e5f00013f9994bdcdd5bc64702a70aa64ea6` | 2026-10-19 | Remote code reads two config fields that make a loader run code without `trust_remote_code`, at any depth of a `config.json`. An attention field (`_attn_implementation_internal`, or `_attn_implementation`, whose setter writes it) naming a Hub kernel repository outside `kernels-community` FAILs as `config-kernel-injection`: transformers 4.56.0 to 5.2.x download and run that kernel in a plain `from_pretrained` once the `kernels` package is installed (CVE-2026-4372), and `save_pretrained` never writes either field. One naming a `kernels-community` kernel, which 5.3.0 and later still load from the field, is a LEAD (`config-hub-kernel`). A truthy `trust_remote_code` is a LEAD (`config-trust-remote-code`): LightGlue's config passed it to the nested `AutoConfig.from_pretrained` for its keypoint detector before transformers 5.5.0, importing another repository's code (CVE-2026-5241), and other loaders ignore it. The row FAILs for the first time. On 403 real repositories, no result changed; see [false-positive-baseline.md](false-positive-baseline.md). |
| `tier1/0.11` | `1fc34539a816d9d2bfdad5005f5991fd08e10eacf4a6960bd6e4c31f0a9dd26f` | 2026-10-15 | No rule change: the Chat template check gains `Triggers`, which returns the literals the content conditions test in each template it grades LEAD, each with the prompts the template renders with it (armed, with the branch firing, and counterfactual, the same conversation without the branch's text), for Tier 2's trigger confirmation (#284, [tier2.md](tier2.md#trigger-confirmation)). It reads the same analysis and renderer the row does and changes no row's status, notes, or findings. |
| `tier1/0.11` | `5a5d7715b241a0f1002ed4e94d442cc5dc79a748d87d03194b0483f2b8b390c7` | 2026-10-15 | Tokenizer config, on a GGUF: a special-token id of -1 written as a 32-bit integer (`0xFFFFFFFF`, signed or not) is the "no token" sentinel, not an id outside the vocabulary, so it no longer FAILs as `special-token-out-of-range`, as `tier1/0.7` did for a negative id in a directory's `config.json`. llama.cpp skips it with a warning, as it skips any id outside the vocabulary, and it names no token. Found on `ggml-org/tiny-llamas` `stories260K.gguf` (padding and separator ids), whose Tokenizer row FAILed on v0.1.0-rc.5. Any other id at or past the vocabulary's size still FAILs. The row's FAIL note no longer says llama.cpp "would misread or reject" every inconsistency: it says llama.cpp refuses a type or score table shorter than the vocabulary, skips a special-token id outside it with a warning, and reads a type it does not define as undefined. The change only removes a FAIL; the benchmark's outcomes are unchanged. See [false-positive-baseline.md](false-positive-baseline.md). |
| `tier1/0.10` | `b7a105c69b51c5acf6c9d23bd9b9b1e209d522a341e759bca4132ddefea38c5c` | 2026-10-14 | A check whose input was not supplied is named, not run. Two rows no longer grade NOT_TESTED for want of an input, and instead are listed in the report's `out_of_scope.not_run` with the reason, as the Tier 2 checks are: Known-bad hash match runs only when a known-bad list is supplied (`SOCAIR_DENYLIST`, or a verified feed that carries one; a list the operator named that is empty or could not be read still gives a NOT_TESTED row), and Chat template runs only when the artifact carries a template (a GGUF's `tokenizer.chat_template`; a directory's `tokenizer_config.json`, `chat_template.json`, or `.jinja` file; a template file that could not be read still gives a row). Neither withholds promotion when its input is absent, as the License policy row does not without a policy: a clean model pulled through the airlock with its provenance is authorized without an acceptance. There is no standing public list of malicious model files to default to, and a model with no template (a base, embedding, or reranker model) has none to check; a template a serving stack supplies is outside the artifact. `report.Validate` refuses a check named both as a row and as not run. The benchmark's outcomes are unchanged: its known-bad case is scanned with a list. |
Expand Down
39 changes: 30 additions & 9 deletions docs/detection-benchmark.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ generated corpus, on 2026-10-04; CI does not re-run them.
scanner here was given any of them. With Socair's defaults (none of the
four), the remapped tokenizer and the near-miss template pass, the known-bad
file is matched against no list (with none supplied, that check does not
run), and the edited weights have no row that compares them, so Socair detects 63 of 73. Scores with the cases that need an input left out
run), and the edited weights have no row that compares them, so Socair detects 65 of 75. Scores with the cases that need an input left out
follow the comparison table.
- **The attacks are defanged.** Each case keeps the attack's structure (the
gadget, the opcodes, the archive trick, the template construct) and swaps its
Expand All @@ -44,7 +44,7 @@ generated corpus, on 2026-10-04; CI does not re-run them.
models are measured separately, on real corpora, in
[false-positive-baseline.md](false-positive-baseline.md).

## Socair (check set tier1/0.11, 2026-10-15)
## Socair (check set tier1/0.12, 2026-10-19)

| Check row | Cases | Detected (FAIL or LEAD) | Withheld as a gap (NOT_TESTED) | Missed (PASS) |
|---|---|---|---|---|
Expand All @@ -54,15 +54,15 @@ generated corpus, on 2026-10-04; CI does not re-run them.
| Hash, provenance, lineage | 1 | 1 | 0 | 0 |
| Known-bad hash match | 1 | 1 | 0 | 0 |
| Pickle opcode scan | 23 | 23 | 0 | 0 |
| Remote code | 9 | 8 | 0 | 1 |
| Remote code | 11 | 10 | 0 | 1 |
| Tensor reference | 1 | 1 | 0 | 0 |
| Tokenizer config | 3 | 3 | 0 | 0 |
| **All** | **73** | **67** | **3** | **3** |
| **All** | **75** | **69** | **3** | **3** |

Benign controls flagged (FAIL or LEAD on any row): 0 of 17.
Benign controls flagged (FAIL or LEAD on any row): 0 of 18.

Four of these detections depend on a reference input (see "Read this first");
with Socair's defaults it detects 63 of 73.
with Socair's defaults it detects 65 of 75.

Check set tier1/0.8 replaced the pickle row's import allowlist with a typed
grammar (`socair-wo/1`, see [check-set.md](check-set.md)) and added three
Expand Down Expand Up @@ -210,6 +210,21 @@ special-token id of -1 (`0xFFFFFFFF`, the "no token" sentinel llama.cpp
skips) from failing the Tokenizer row as an id outside the vocabulary; every
case and control here writes its special-token ids inside the vocabulary.

Check set tier1/0.12 adds two Remote code cases for config fields that make
transformers run code with `trust_remote_code=False` (#291).
`dir-config-kernel-injection` names an attacker's Hub kernel in
`_attn_implementation_internal`, the CVE-2026-4372 shape, which transformers
4.56.0 to 5.2.x download and run in a plain `from_pretrained`. It is the
row's first FAIL: `save_pretrained` never writes the field, so the field is
the injection. `dir-config-trust-remote-code` is a LightGlue config that
grants `trust_remote_code` to the keypoint detector it loads from another
repository, the CVE-2026-5241 shape. It is a LEAD, because the published
LightGlue DISK checkpoint sets the same field on purpose. Under tier1/0.11
both PASSed: neither ships a `.py` file or an `auto_map`. The
`control-dir-attention-field` control pins a `config.json` whose
`_attn_implementation` names one of the library's own implementations, as
`microsoft/Phi-4-multimodal-instruct` ships. No earlier case changed outcome.

| Case | Format | Technique | Row | Result | Severity |
|---|---|---|---|---|---|
| `control-pickle` | pickle | benign state-dict-shaped pickle written by CPython | (control: every row) | PASS | |
Expand All @@ -227,6 +242,7 @@ case and control here writes its special-token ids inside the vocabulary.
| `control-openvino` | openvino | benign OpenVINO IR .xml on its own: standard operations, its weights in a .bin beside it | (control: every row) | PASS | |
| `control-dir-openvino` | model directory | benign directory with an openvino/ export as sentence-transformers ships: an f32 IR and an int8 one whose Consts share a range | (control: every row) | PASS | |
| `control-dir-training-script` | model directory | benign directory with train_script.py, as sentence-transformers ships, that no loader imports | (control: every row) | PASS | |
| `control-dir-attention-field` | model directory | benign config.json whose _attn_implementation names flash_attention_2, as Phi-4-multimodal ships | (control: every row) | PASS | |
| `control-dir-checksums` | model directory | benign directory with an uploader's SHA256SUMS that matches every file | (control: every row) | PASS | |
| `pickle-os-system-p2` | pickle | os.system via GLOBAL + REDUCE, protocol 2 | Pickle opcode scan | FAIL | critical |
| `pickle-os-system-p4` | pickle | os.system via STACK_GLOBAL, protocol 4 (the Python 3.8+ default) | Pickle opcode scan | FAIL | critical |
Expand Down Expand Up @@ -285,6 +301,8 @@ case and control here writes its special-token ids inside the vocabulary.
| `dir-remote-code-imported` | model directory | auto_map naming a clean module that imports repository code that runs a command | Remote code | LEAD | medium |
| `dir-remote-code-other-repo` | model directory | auto_map naming code in another repository, which the loader fetches | Remote code | LEAD | medium |
| `dir-remote-code-outside-path` | model directory | auto_map naming a module by an absolute path outside the directory | Remote code | LEAD | medium |
| `dir-config-kernel-injection` | model directory | config.json naming an attacker's Hub kernel in _attn_implementation_internal | Remote code | FAIL | critical |
| `dir-config-trust-remote-code` | model directory | a LightGlue config.json that grants trust_remote_code to the keypoint detector it loads from another repository | Remote code | LEAD | medium |
| `dir-st-custom-module` | model directory | a sentence-transformers module in modules.json that runs a command, with no auto_map | Remote code | LEAD | medium |
| `dir-custom-generate` | model directory | custom_generate/generate.py that runs a command, named by no config | Remote code | LEAD | medium |
| `dir-inference-handler` | model directory | an Inference Endpoints handler.py that runs a command, imported without trust_remote_code | Remote code | LEAD | medium |
Expand Down Expand Up @@ -352,9 +370,9 @@ the two added with #262 (`dir-weights-edited` and the
`control-dir-tensor-reference` control), the six ONNX cases and controls
added with #264, the two added with #263 (`dir-checksum-swapped` and the
`control-dir-checksums` control), the seven OpenVINO cases and controls
added with #268, and the ten Keras cases and controls added with #269, so its
counts cover the cases before them; the other scanners have not been run on
those forty-eight. A *suspicious* result counts as a finding, as Socair's LEAD does:
added with #268, the ten Keras cases and controls added with #269, and the
three config-field cases and controls added with #291, so its counts cover the
cases before them; the other scanners have not been run on those fifty-one. A *suspicious* result counts as a finding, as Socair's LEAD does:
picklescan's suspicious globals and Fickling's SUSPICIOUS. "Not scanned" means
the tool skipped the file, could not parse it, or does not support the format.

Expand Down Expand Up @@ -441,6 +459,7 @@ and the two formats they belong to read, from that run:
| `control-dir-checksums` | clean | not run | not run | not run | not run |
| `control-dir-torchscript` | clean | not run | not run | not run | not run |
| `control-dir-training-script` | clean | not run | not run | not run | not run |
| `control-dir-attention-field` | clean | not run | not run | not run | not run |
| `control-dir-tensor-reference` | clean | not run | not run | not run | not run |
| `control-gguf` | clean | clean | clean | finding (not a pickle) | could not scan |
| `control-model-directory` | clean | clean | could not scan | could not scan | could not scan |
Expand All @@ -467,6 +486,8 @@ and the two formats they belong to read, from that run:
| `dir-remote-code-imported` | finding | not run | not run | not run | not run |
| `dir-remote-code-other-repo` | finding | not run | not run | not run | not run |
| `dir-remote-code-outside-path` | finding | not run | not run | not run | not run |
| `dir-config-kernel-injection` | finding | not run | not run | not run | not run |
| `dir-config-trust-remote-code` | finding | not run | not run | not run | not run |
| `dir-st-custom-module` | finding | not run | not run | not run | not run |
| `dir-custom-generate` | finding | not run | not run | not run | not run |
| `dir-inference-handler` | finding | not run | not run | not run | not run |
Expand Down
6 changes: 5 additions & 1 deletion docs/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ artifact:
`pipeline.py`, or `code/inference.py` at the root); and every repository file
those import, transitively. A reference to another repository or outside the
directory is a LEAD too. Any other `.py` file is listed in the notes, not
judged (`internal/checks/remotecode`, #254).
judged (`internal/checks/remotecode`, #254). Two `config.json` fields run
code without `trust_remote_code` at all (#291): a Hub kernel outside
`kernels-community` named as the attention implementation FAILs
(CVE-2026-4372), and a `kernels-community` kernel there, or a truthy
`trust_remote_code` (CVE-2026-5241), is a LEAD.
- The tokenizer is inspected from `tokenizer.json`, `tokenizer_config.json`,
`special_tokens_map.json`, and the special-token ids in `config.json` and
`generation_config.json` (`tokenizer.InspectHF`): inconsistent tables FAIL,
Expand Down
Loading
Loading