Skip to content
Merged
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
20 changes: 20 additions & 0 deletions apps/maple-agent/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ all-features = true
# notices are tracked separately because they often require API migrations.
unsound = "all"
unmaintained = "none"
# Native Agent reachability review: docs/zstd-advisories.md. These exceptions
# cover only the listed findings in zstd 0.13.3 / zstd-safe 7.2.4 / zstd-sys
# 2.1.0, used by the store codec and pinned CUA cursor-overlay. Re-review on
# dependency/pin, feature, call-site, or target changes; remove after upgrading.
ignore = [
{ id = "RUSTSEC-2026-0391", reason = "Both consumers create fresh owned contexts; borrowed with_context reuse is unused" },
{ id = "RUSTSEC-2026-0395", reason = "StableInBuffer is never enabled; ordinary encoders select only CompressionLevel" },
{ id = "RUSTSEC-2026-0396", reason = "Seekable and seek-table APIs and the seekable feature are unused" },
{ id = "RUSTSEC-2026-0397", reason = "Consumers use OutBuffer::around at position zero, not around_pos beyond an initialized Vec" },
{ id = "RUSTSEC-2026-0398", reason = "No seekable decompression or caller-selected seek offsets" },
{ id = "RUSTSEC-2026-0399", reason = "No experimental init_using_cdict/init_using_ddict or borrowed prepared dictionaries" },
{ id = "RUSTSEC-2026-0400", reason = "No context mixes one-shot low-level calls with an unfinished stream" },
{ id = "RUSTSEC-2026-0401", reason = "Dictionary training is unused; no untrusted sample-size arrays reach train_from_buffer" },
{ id = "RUSTSEC-2026-0402", reason = "No CCtx::try_clone or NbWorkers setting; experimental and zstdmt features are unused" },
{ id = "RUSTSEC-2026-0403", reason = "Both consumers use read::Decoder, explicitly excluded by the advisory; initialized slice output is used" },
{ id = "RUSTSEC-2026-0404", reason = "No experimental DCtx::try_clone or prepared-dictionary cloning" },
{ id = "RUSTSEC-2026-0405", reason = "No SeekableCStream API or invalid caller-selected InBuffer position" },
{ id = "RUSTSEC-2026-0406", reason = "Only fresh single-worker contexts are configured before streaming; no unfinished multithreaded frame" },
{ id = "RUSTSEC-2026-0410", reason = "The faulty allocator shim is wasm32-only; Agent targets native macOS, Linux and Windows" },
]

[bans]
# Emergency supply-chain containment for the August 2026 crates.io campaign.
Expand Down
70 changes: 70 additions & 0 deletions apps/maple-agent/docs/zstd-advisories.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Native Agent zstd advisory exceptions

The exceptions in `../deny.toml` apply to the 14 findings below, reviewed against
`zstd 0.13.3`, `zstd-safe 7.2.4`, and `zstd-sys 2.1.0+zstd.1.5.7` on the native
macOS, Linux, and Windows targets. Other vulnerability/unsoundness findings and
the package bans remain blocking. This policy does not apply to Maple Research's
separate graph.

These are real upstream defects. Source review found no triggering path in the
Agent's selected APIs, features, context state, and native platforms. This is a
bounded reachability assessment, not an exploit test or a claim that all uses of
these dependency versions are safe. The patched upstream versions are
`zstd 0.14.3`, `zstd-safe 8.2.0`, and `zstd-sys 2.1.2`.

## Reviewed consumers

The Agent lockfile has exactly two direct zstd consumers and no independent
zstd-safe or zstd-sys consumer:

- [`store/codec.rs`](../crates/maple-agent/src/store/codec.rs) uses
`stream::encode_all(bytes, 3)` and `stream::read::Decoder::new`, with a bounded
read into a separate caller-owned vector. Each operation creates a fresh owned
context. Attachment-migration tests also use `encode_all`.
- CUA `cursor-overlay`, pinned at
[`2a3975570a885f45ef83f7e81bba54a01804ebd0`](https://github.com/trycua/cua/blob/2a3975570a885f45ef83f7e81bba54a01804ebd0/libs/cua-driver/rust/crates/cursor-overlay/src/theme_artifact.rs#L294-L350),
uses `encode_all` at level 12 for theme authoring and `read::Decoder` for theme
loading. Custom themes can be external files; the assessment does not assume
that compressed inputs are trusted.

Both dependencies request ordinary zstd features. `experimental`, `seekable`,
and `zstdmt` are not requested. Dictionary-building support is enabled by
default, but neither consumer calls its training API. The selected decoding
adapter creates valid input buffers and initialized slice output at position
zero; it does not supply an uninitialized caller vector to zstd-safe. Encoding
uses its internal output vector safely at position zero.

## Finding-specific rationale

The links pin the reviewed RustSec database snapshot, rather than treating an
advisory's package-version match as proof of a reachable product defect.

| Advisory | Required path or state absent from the reviewed Agent |
| --- | --- |
| [0391](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd/RUSTSEC-2026-0391.md) | Borrowed `with_context` reuse. Both consumers create fresh owned contexts; `encode_all` finishes its stream. |
| [0395](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0395.md) | Enabling `StableInBuffer`. The ordinary encoders select only the compression level. |
| [0396](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0396.md) | Seekable decoding or seek-table access. These APIs and the feature are unused. |
| [0397](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0397.md) | `OutBuffer::around_pos` with a gap beyond an initialized vector. The selected adapters use `around` at position zero. |
| [0398](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0398.md) | Seekable decompression with a caller-selected offset. Neither consumer uses it. |
| [0399](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0399.md) | Experimental borrowed prepared-dictionary initialization. Ordinary wrappers load empty dictionary bytes into fresh contexts instead. |
| [0400](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0400.md) | Mixing low-level one-shot methods with an unfinished stream on the same context. `encode_all` is internally streaming and does not do this. |
| [0401](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0401.md) | Dictionary training using untrusted sample-size arrays. The available training API is never called. |
| [0402](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0402.md) | Experimental `CCtx::try_clone` with multithreaded context state. No clone or `NbWorkers` setting is used. |
| [0403](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0403.md) | The generic decompression method is reached, but the vulnerable vector-output path is absent. The advisory explicitly excludes `read::Decoder`; its reader uses an initialized slice and propagates errors before returning written bytes. |
| [0404](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0404.md) | Experimental `DCtx::try_clone`, dictionary/prefix cloning, or mid-frame cloning. These APIs are unused. |
| [0405](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0405.md) | Seekable compression with an invalid caller-selected input-buffer position. The seekable API is unused. |
| [0406](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-safe/RUSTSEC-2026-0406.md) | Changing a context with an unfinished multithreaded frame. Settings are applied only to fresh single-worker contexts before streaming. |
| [0410](https://github.com/RustSec/advisory-db/blob/a78282a1414d6c28cc228c4eae3570451affb0dc/crates/zstd-sys/RUSTSEC-2026-0410.md) | The affected allocator module is compiled only for `wasm32`. The supported Agent targets are native. |

## Re-review and removal

Re-review the complete exception list whenever either consumer, the CUA revision,
the resolved compression versions/features, or the supported target list changes.
In particular, borrowed context reuse, write-side decoders, dictionary training,
prepared dictionaries, seekable/experimental APIs, context cloning, worker
configuration, or a Wasm target invalidate the relevant reasoning above.

Remove each exception once all affected locked packages have been upgraded to
patched versions. Run `scripts/audit-sqlcipher-dependencies.py` against a current
advisory database for each supported target after changing this policy. Keep new
advisories blocking; these entries do not authorize accepting future findings.
Loading