Skip to content

Improve untrusted MAST overspec warning - #3418

Open
huitseeker wants to merge 4 commits into
debug-info-hostile-wire-tddfrom
warn-untrusted-mast-overspec
Open

Improve untrusted MAST overspec warning#3418
huitseeker wants to merge 4 commits into
debug-info-hostile-wire-tddfrom
warn-untrusted-mast-overspec

Conversation

@huitseeker

@huitseeker huitseeker commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

On top of #3460. Closes #3425.

This PR changes the untrusted MAST forest overspec log from error! to warn!, adds caller location to the warning, and aligns package trusted readers with their names.

This PR hardens package deserialization across trust boundaries.

Untrusted package reads now validate the embedded MAST forest, decode package DebugInfo within fixed bounds, validate it against the package, and retain it only after that succeeds.

Trusted package reads now mean what the name says. They trust the embedded MAST and manifest links, preserve package debug sections, and skip the cross-checks meant for hostile input.

The MAST warning is narrower : if an untrusted MAST forest includes wire hashes, we log warn! with the caller location. The input is still accepted and validated by recomputing hashes. The warning is about wasted untrusted bytes, not corruption.

Package::read_from remains the untrusted reader for packages where debug sections are not needed. It validates the MAST and drops package debug sections.

Package::read_from and Package::read_from_bytes are the untrusted readers. They validate MAST and package debug info before returning the package.

Package::read_from_untrusted and Package::read_from_bytes_untrusted are new. They validate the MAST and package debug sections, then keep debug info.

No separate untrusted reader was added. The existing Package::read_from and Package::read_from_bytes keep that role.

Package::read_from_unchecked and Package::read_from_bytes_unchecked remain the way to trust bytes completely.

Package::read_from_unchecked and Package::read_from_bytes_unchecked were removed. Use Package::read_from_trusted and Package::read_from_bytes_trusted for same-domain trusted package bytes.

The DebugInfo path now rejects oversized payloads, oversized string and type tables, oversized strings, invalid references, bad spans, invalid layouts, and unsafe lookup shapes. Fuzz targets and regression seeds cover those hostile inputs.

@huitseeker
huitseeker requested review from bitwalker and bobbinth July 23, 2026 11:25
@huitseeker
huitseeker force-pushed the warn-untrusted-mast-overspec branch 3 times, most recently from 76870fe to 87c0e82 Compare July 23, 2026 20:02

@bitwalker bitwalker left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good, I do have a few questions though (see comments)

let package = MastPackage::read_from_bytes_trusted(&bytes)
.map_err(|error| Report::msg(error.to_string()))?;
let package =
MastPackage::read_from_bytes(&bytes).map_err(|error| Report::msg(error.to_string()))?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this should use read_from_bytes_trusted - implicitly the dependency graph is operating on trusted packages (they are referenced either explicitly by the user, assembled on-demand and cached, or are loaded from a user-provided registry).

This is exactly the sort of issue I was running into - some code might defensively say "I'm not sure if I should assume trust, so I'm going to use the safer choice", but this would result in errors getting logged. Now that those errors are warnings, it's marginally better, but it's still essentially out of the control of the caller to say "this package is trusted", and I think it's fair to assume packages are trusted here.

@huitseeker huitseeker Jul 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated to use a narrower reader than read_from_bytes_trusted: it validates MAST and manifest data, but preserves trusted local debug sections.

Comment thread crates/package-registry-local/src/lib.rs
log::warn!(
"Package read ignored debug sections from an untrusted artifact; use Package::read_from_trusted for local cache/debug reads"
);
log::warn!("Package read ignored debug sections from an untrusted artifact");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's unclear to me why we treat debug info like this? It should just be another custom section, just one that various built-in facilities recognize - in other words, what is special about the debug info section that warrants stripping it out?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Package::read_from stays the untrusted reader. It validates MAST and drops debug sections because as of today we do not know how to verify debug info adversarially (what sort of resource exhaustion could it create in any of its downstream processing, not limited to deserialization?). Keeping it would make unverified debug data look trusted.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That feels to me like a job for Package::debug_info, not Package::read_from - we're not deserializing the debug section here, and at this point it is no different than any other section.

The trust boundary here is really about the package metadata and the MAST - the parts it actually has to process when this is called. By conflating the two we're stripping out one of the most valuable pieces of the package silently.

Comment thread core/src/mast/untrusted.rs
@huitseeker
huitseeker force-pushed the warn-untrusted-mast-overspec branch from 355d636 to fe1b216 Compare July 24, 2026 14:09

@bitwalker bitwalker left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should stop stripping debug info when deserializing Package via read_from (i.e. the untrusted path), and instead punt that responsibility to Package::debug_info when we actually deserialize that data.

Currently, we're unintentionally stripping debug info in various places, silently, and it will be super confusing.

@melnikga

melnikga commented Aug 4, 2026

Copy link
Copy Markdown

Related: #3425 same diagnostic, reported from the miden client CLI side

Demote the overspecified untrusted MAST diagnostic to a warning and include the tracked caller location.

Clarify package trusted reader docs and add the local design note with origin/next permalinks.
@huitseeker
huitseeker force-pushed the warn-untrusted-mast-overspec branch from d2fcca5 to 6064ff4 Compare August 4, 2026 15:26
@huitseeker
huitseeker changed the base branch from next to debug-info-hostile-wire-tdd August 4, 2026 15:28
@huitseeker
huitseeker requested a review from bitwalker August 7, 2026 18:21
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.

MAST deserialization logs UntrustedMastForest overspecification at ERROR on a successful path

3 participants