Skip to content

test(fuzz): add dedicated parse_idlist fuzz targets and make the README claim true - #4

Draft
h4x0r wants to merge 3 commits into
mainfrom
feat/fuzz-parse-idlist
Draft

test(fuzz): add dedicated parse_idlist fuzz targets and make the README claim true#4
h4x0r wants to merge 3 commits into
mainfrom
feat/fuzz-parse-idlist

Conversation

@h4x0r

@h4x0r h4x0r commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

README.md claimed the crate was "fuzzed over parse_idlist". It was not — fuzz/fuzz_targets/ was empty and git log --all -- fuzz returned nothing, so no target ever existed. docs/decisions/0003-panic-free-forbid-unsafe-parsing.md recorded this honestly as a known gap.

This PR closes the gap rather than softening the claim, then updates the docs to say what is measured.

What changed

New fuzz/ harness — two targets:

Target Drives
idlist parse_idlist alone — the cb framing loop, class dispatch, per-class decoders, 0xbeef0004 extension block
pipeline parse_idlistreconstruct_pathdisplay_name — the joins and label selection over lossily-decoded UTF-16

Patterned from lnk-forensic and shellhist-forensic (target naming, CI job shape) and xpress-huffman / safe-read (single-crate fuzz manifest with path = "..", standalone [workspace]).

CI gains a nightly smoke-fuzz job matching the sibling repos — cargo fuzz check to build all targets, then 30s per target on every PR. cargo-fuzz installs via the same pinned taiki-e/install-action already used here for cargo-llvm-cov, rather than an unpinned cargo install.

DocsREADME.md, docs/index.md, docs/PRD.md and ADR 0003 now describe the harness that exists.

Measured results

Both targets ran clean on first use. No crashes found.

idlist    8,229,495 executions in 121s
pipeline  9,131,724 executions in 121s

Local, aarch64-apple-darwin, libFuzzer, -max_total_time=120 -rss_limit_mb=4096.

This is present-robustness evidence over the inputs libFuzzer reached in that budget. It does not prove that no panicking input exists, and the docs say so — the static lints (unsafe_code = "forbid", unwrap_used/expect_used denied) remain the load-bearing guarantee, with the fuzzer as the empirical partner.

On incidental coverage

lnk-forensic and winreg-forensic both depend on shellitem and have real fuzz harnesses that reach this code through their own readers. That does not make a first-person "fuzzed over parse_idlist" true — the claim asserts a dedicated harness, so one was added.

Two smaller corrections found along the way

  • CONTRIBUTING.md instructed contributors to run cargo +nightly fuzz run shelllink # or: forensiclnk-forensic's target names, carried over when this repo's scaffolding was copied from it. Wrong here even once targets existed.
  • The README cited #![forbid(unsafe_code)] as an inner attribute; the lint is declared in Cargo.toml [lints.rust] as unsafe_code = "forbid". Same guarantee, but a reader grepping for the attribute would not have found it.

ADR 0003 and docs/PRD.md also both stated "there is no ci.yml yet" — already stale, since ci.yml runs clippy -D warnings, the low-MSRV job and the coverage gate today. Corrected in the same pass.

Gate

cargo build · cargo test (31 passed) · cargo clippy --all-targets --all-features -- -D warnings · cargo fmt --all --check · cargo +nightly fmt --check in fuzz/ — all green.

🤖 Generated with Claude Code

h4x0r and others added 2 commits August 1, 2026 16:22
The README, docs/index.md and the CHANGELOG all advertised "fuzzed", but
fuzz/fuzz_targets/ was empty and no target existed anywhere in history —
ADR 0003 recorded this honestly as a known gap. ADR-0012 requires a fuzz
target per parsed structure for any crate that parses untrusted input, and
shell-item blobs are lifted verbatim from .lnk LinkTargetIDList structures
and registry ShellBags values.

Two targets, following the fleet pattern (lnk-forensic, shellhist-forensic
for the naming and CI job; xpress-huffman, safe-read for the single-crate
fuzz manifest with path = ".."):

  idlist    parse_idlist alone — the cb framing loop, the class dispatch,
            the per-class decoders and the 0xbeef0004 extension block.
  pipeline  parse_idlist to reconstruct_path to display_name — the joins
            and label selection over lossily-decoded UTF-16, where a
            char-boundary assumption would surface rather than in parse.

lnk-forensic and winreg-forensic already fuzz harnesses that reach this
code incidentally through their own readers; that is not a substitute for
a dedicated target and does not make a first-person claim true.

Both run clean on first use, with no crashes found:

  idlist    8,229,495 executions in 121s
  pipeline  9,131,724 executions in 121s

(local, aarch64-apple-darwin, libFuzzer, -max_total_time=120). No crashes
in N executions is present-robustness evidence over the inputs libFuzzer
reached; it does not prove that no panicking input exists. The static
lints remain the load-bearing guarantee.

CI gains a nightly smoke-fuzz job matching the sibling repos, building all
targets with `cargo fuzz check` then running each for 30s on every PR.
cargo-fuzz is installed via the same pinned taiki-e/install-action already
used for cargo-llvm-cov rather than an unpinned `cargo install`.

CONTRIBUTING named `shelllink` and `forensic` — lnk-forensic's target
names, carried over when this repo's scaffolding was copied from it, and
wrong here even once targets existed. Corrected to idlist and pipeline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The published README asserted the crate was "fuzzed over `parse_idlist`"
while no fuzz target existed. The preceding commit made a dedicated target
real; this makes the documentation say what is actually true and measured
rather than merely asserted.

README "Trust but verify" moves to the fleet's canonical paired-bullet
form: a Fuzzed bullet carrying the empirical evidence (both target names,
what each drives, and the exec counts reached) beside a Panic-free-by-lint
bullet carrying the static posture. Per the fleet's evidence-based-rigor
rule these are complementary, not interchangeable — the lints make panics
unreachable by construction, the fuzzer tests that empirically over a
finite number of inputs.

Also corrected in the same sentence: the README cited
`#![forbid(unsafe_code)]` as an inner attribute, but the lint is declared
in Cargo.toml `[lints.rust]` as `unsafe_code = "forbid"`. Same guarantee,
but a reader grepping for the attribute would not have found it.

ADR 0003's "Known gap" consequence and docs/PRD.md's validation section
both said no fuzz target was committed and no ci.yml existed. The fuzz
half is closed by the preceding commit; the ci.yml half was already stale,
since ci.yml runs clippy -D warnings, the low-MSRV job and the coverage
gate today. Both now describe the current state, and both keep the limit
of the evidence explicit rather than reading the exec counts as proof of
absence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@socket-security

socket-security Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedlibfuzzer-sys@​0.4.134710093100100

View full report

…ot musl

The fuzz job failed on the first CI run:

  error: sanitizer is incompatible with statically linked libc,
         disable it using `-C target-feature=-crt-static`
  error[E0463]: can't find crate for `std`
  note: the `x86_64-unknown-linux-musl` target may not be installed

I had installed cargo-fuzz via the pinned taiki-e/install-action already used
in this workflow for cargo-llvm-cov, preferring local consistency. That is the
cause: the prebuilt Linux cargo-fuzz binary is musl-linked, and cargo-fuzz
defaults --target to its own build triple, so it tried to build the targets for
x86_64-unknown-linux-musl. libFuzzer's sanitizers cannot link against a static
libc, and the musl std was not installed either.

`cargo install cargo-fuzz` compiles on the runner and therefore picks up the
gnu host triple. That is what lnk-forensic and shellhist-forensic do, and their
"Fuzz targets (nightly smoke)" jobs are green — matching the fleet was the right
call here and deviating from it was mine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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