Keep the exact producer expression and report unknown symbol identity when chained-import text cannot distinguish a binding addend from a literal name suffix.
Fixes#6648
BREAKING CHANGE: inspect_macho import names can be null when identity is ambiguous. Use raw_name for the observed expression and name_status to distinguish it from an exact symbol name.
Accumulate length octets arithmetically so a four-octet length with bit 31 set remains a positive unsigned value and is rejected by the containing-range check rather than becoming a negative length.
Share the bounded BER tree reader between PE certificates and APK v1 CMS, then accept constructed OCTET STRING signature values while retaining the declared signer and certificate facts. Embedded X.509 certificate decoding keeps its DER requirement.
Fixes#6603
* fix(flutter): honor ELF note alignment when reading build IDs
* test(flutter): key shared note ranges by effective alignment
Cover a program and section declaration that share one note range: differing effective alignments (8 and 4) must both be read, while declarations that both normalize to four bytes (1 and 4) still share one read. 24-byte build IDs pad identically at both alignments, so only the range key decides the read count.
* fix(native): preserve whitespace in otool load-command strings
otool prints dylib install names and rpaths as `<key> %s (offset %u)`
with exactly one separator space around the recorded string. The parser
trimmed the value and stripped the offset suffix with `\s+`, so a valid
install name such as " leading.dylib " became "leading.dylib" in both
the dependency inventory and the raw load-command fields.
Parse these offset-suffixed string fields by their exact format and
strip only the single-space offset suffix.
Fixes#3384
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): verify exact Mach-O install names through CLI and MCP
---------
Co-authored-by: Bhaaraadwaj <bharadwajdaya@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): admit thin arm64_32 Mach-O targets for static inspection
Target admission mapped Mach-O CPU types only to x86, x86_64, arm and
arm64, so a thin arm64_32 object was rejected as "unsupported Mach-O
architecture" before list-architectures, inspect-macho or
inspect-signature could run, although the same slice inside a FAT file
was inventoried.
Recognize CPU_TYPE_ARM64_32 as its own Mach-O-only architecture with a
dedicated thin target variant, so ELF, PE and raw-binary paths cannot
carry it. Add its slice policy so 32-bit dispatch metadata refuses it
like other 32-bit Mach-O images instead of reporting a CPU mismatch.
Ghidra, Hopper and IDA have no verified arm64_32 lane and decline it
explicitly; Hopper's declined families now share one predicate.
Fixes#5713
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ci(apple): run the thin arm64_32 CLI regression on macOS
The regression compiles an arm64_32 object with Apple clang, so it skips
on the Ubuntu jobs. List it in the macOS Apple artifact job and its
change scope so the job runs it and changes to it select that job.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): report Linux-only integrations as unsupported_host off their hosts
Session discovery folded the host check into each optional integration's
enabled flag, so on macOS or Windows the Linux-only packet, signal,
firmware, pwntools, EVM and Wakaru tools reported provider_missing.
Their execution guards refuse those hosts whatever is configured, so
installing a provider there could never make them available.
The server now records, per integration, when the host is outside its
verified host and no service is injected. Discovery checks that before
configuration and reports unsupported_host with the existing
remediation. Injected services and supported hosts behave as before.
Fixes#5730
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(mcp): share provider host checks with session discovery
Discovery restated each Linux-only integration's host rule in
createServer while its provider kept a separate execution check, so the
two could drift apart again. Each provider now exports its host
predicate, uses it in its execution guard, and composition hands the
same predicate to createServer for both the host restriction and the
enabled flag.
Observed host restrictions now also apply when an embedder supplies its
own availability policy, as provider load failures already do, because
no policy lets the default providers pass their host checks.
The MCP regression moves to tests/process-global and emulates darwin
arm64, linux arm64 and linux x64 through the real createServer, so CI on
Linux x64 exercises the unsupported-host branch. It also covers a
configured policy and the matching execution refusals.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(mcp): keep caller host restrictions beside observed ones
The observed host restriction replaced a configured policy's whole
hostUnsupported map. For an injected service the observed value is
false, so a caller's own restriction was lost and the tool was reported
available. Combine both per integration: either the caller or the
observed host can mark it unsupported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pcap): expect unsupported_host for packet tools off Linux
The host-independent PATH case asserted provider_missing on every host.
Off Linux the packet tools are unavailable because of the host, so
discovery now reports unsupported_host there; Linux still reports
provider_missing for an unusable PATH.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
nm -j and dyld_info -exports end each row with LF. Splitting on \r?\n and
trimming rows treated a carriage return at the end of a symbol name as part
of the line terminator, so the distinct exports "trailing\r" and
"trailing" merged into one entry with the wrong address. Split rows on LF
only and keep trailing text in export rows.
Fixes#3390
* fix(native): keep truncated empty class-import scans partial
An explicitly present empty objc_class_import_addresses list with
objc_class_import_addresses_complete false reported binding coverage as
not_requested with a null reason, discarding the caller's declaration that
the candidate scan was truncated. Only an omitted list, or an empty list
declared complete, is not a request; a truncated empty scan now reports
partial coverage with the existing record-budget reason and zero examined
and decoded addresses.
Refs #6086
* test(native): cover empty truncated class-import candidate scans
Refs #6086
* fix(hopper): retain file-offset reads when descriptor close fails
A rejected source close was classified as a source or access failure and
dropped the descriptor, so client close reported success. Keep the
completed snapshot or the earlier non-regular-source failure, report the
close as typed cleanup, and retry that exact handle.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): retain LLDB prelaunch cleanup ownership
Preparation failures were rewritten as an LLDB exit, and discovery
failures dropped the resolver supervisor. Preserve compiler facts and
the foreign helper marker, and retry only the tracer-owned resolver
before another trace is admitted.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(hopper): bind combined close failures to both owners
A descriptor close and a session close that fail together now stay incomplete until each owner resolves.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): retain resolver preparation cleanup ownership
LLDB discovery keeps compiler facts and the foreign helper marker when tool resolution fails during preparation.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Remove the Latin-1 fallback and the assumed UTF-8 decoding of GeneralString so unsupported name encodings cannot silently corrupt issuer or subject text. Document the limitation and cover the T.61 acute-accent example through the public CLI.
Validation: 30 focused parser/CLI/MCP tests passed; npm run check and npm run docs:check passed. Three new parser regressions fail on the original decoder. Full suite and real historical certificates were not exercised.
* feat(pe): inspect Authenticode certificate tables
Add inspect_pe_certificates for IMAGE_DIRECTORY_ENTRY_SECURITY
WIN_CERTIFICATE entries and structurally decoded PKCS#7 signer
and X.509 identity fields. The workflow reads a stable PE image
without executing it or verifying signatures, chains, timestamps,
or Authenticode digest coverage.
* fix(pe): bound and validate certificate DER decoding
- Cap decoded DER values with a shared node budget so sibling fan-out
cannot exhaust memory before the PKCS#7 check
- Require SignedData version, encapContentInfo and a final signerInfos
SET in RFC 5652 order, and a signature OCTET STRING in each SignerInfo
- Decode OBJECT IDENTIFIER arcs as unbounded base-128 values, including
a multi-byte first combined arc
- Decode UniversalString names as UTF-32BE and reject invalid values
- Share PE header admission with the resource layout so a section table
that does not fit SizeOfHeaders is rejected
* docs: list PE certificates in the translated READMEs
* fix(pe): cap OBJECT IDENTIFIER length and arc size
A crafted type-2 certificate with a 262,144-byte contentType OID stalled
decodeOid for about 20 seconds, because one arc kept growing a BigInt
before the signedData check ran. decodeOid now rejects an OID longer than
256 bytes and an arc longer than 32 bytes before decoding it. Certificate
OIDs, including 2.25 UUID arcs, fit under both caps.
* fix(pe): reject truncated certificate tables and PKCS#7
SignedData now requires one SignerInfo with a non-empty signature and a
complete issuerAndSerialNumber. Certificate names share a 64 KiB decoded-byte
budget and are copied once. A security directory that ends in a short
WIN_CERTIFICATE header fails instead of reporting a complete table. The
certificate CLI forwards the caller abort signal into cleanup.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* chore(ci): keep fork workflow files unchanged
The certificate restack follows current main. Workflow files stay at the
fork tip so this branch update does not rewrite .github/workflows.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(pe): charge serial and validity text to the decoded budget
Certificate and signer serial numbers and validity times now count against
the shared decoded-text budget before they are converted, so a crafted
certificate cannot push megabytes of text into the hashed evidence. The
budget error now names certificate text rather than only names.
Restore the CI workflow to match main: the CI_TIMING_TIER input, the
tier-named timing artifacts and their publication conditions, the Windows
typecheck, and the path and snapshot suites in the curated Windows lane.
* fix(pe): require certificate fields and preserve signer key ids
Reject X.509 records that omit subjectPublicKeyInfo or signatureValue,
return subjectKeyIdentifier bytes as bounded hex, and advertise an absolute
path in the PE certificate input schema.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(pe): reject extra PKCS#7 wrappers and invalid UTF-8 names
ContentInfo and its signedData wrapper no longer ignore trailing values, and
directory strings must round-trip as UTF-8 instead of becoming U+FFFD.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(native): read PE and ELF export tables
Add a host-independent export-table reader on the shared native
container layer. PE images report each used export-address-table slot
with its ordinal, one row per name, its address or forwarder text, and
the export directory identity; the PE image reader now exposes its data
directories. ELF images report defined default/protected global, weak
and unique .dynsym symbols with type, binding and .gnu.version_d
version (hidden versions kept distinct, unreadable version tables
"unknown"). Unreadable entries are counted in issues and make coverage
partial; an ELF without section headers is unsupported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(native): inspect native export tables through CLI and MCP
Expose the reader as inspect_native_exports / inspect-native-exports:
one stable, digest-bound read of an explicit file with a caller-selected
input budget, typed failures for malformed, unsupported, oversized and
cancelled reads, and observed Evidence bound to the file path and
SHA-256. Mach-O inputs point to inspect_macho.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(native): describe portable PE and ELF export inventories
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): bound export inventories and read header-backed PE tables
Address review of the export-table reader:
- Charge every retained row and its name, forwarder and version text
against shared 262144-row and 16 MiB allowances before storing it, so
repeated long names or PE aliases cannot exhaust memory.
- Map PE RVAs through the headers as well as sections; the PE image
reader now exposes its SizeOfHeaders mapping.
- Keep ELF exports with version "unknown" when .gnu.version lies outside
the file, and report an empty version-definition name as unresolved.
- Reject a .dynsym without its mandatory null entry as malformed.
- Decode the ELF section directory once.
- Correct the docs on which gaps drop rows and which keep them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(native): decode Swift nominal type declarations from __swift5_types
Fill swift_decls from the nominal type context descriptors that survive
stripping: kind (class, struct, enum, actor), own and qualified name,
module, generic flag, anonymous-context flag, metadata accessor and
descriptor location, with evidence citing the type record. Unresolved
parent contexts keep qualified_name null and the entry partial.
One shared reader walks each context once; class vtable recovery now
consumes its descriptors instead of re-reading the records, so a type
record that cannot be read keeps both facets partial. Remove the
never-populated swift_decls fields that descriptors do not carry.
Fixes#5341
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): bound Swift context walks and decode vtables in record order
Address review of the nominal-type reader:
- Cache intrinsic context depth (distance to the module) so a cached
parent cannot bypass the 32-context bound, and never cache a stop that
depends on where the walk began. Bound qualified names to 4096
characters so nesting cannot multiply name storage.
- Visit each descriptor as soon as its kind and name are read, so a
class vtable spends the record budget in record order instead of after
every later declaration.
- Report an accessor outside executable mapped code as null and keep the
declaration partial.
- Forward a name failure to vtable coverage only when the record is a
class or its kind is unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Inspect selected ELF32/ELF64 PT_NOTE and SHT_NOTE declarations without executing
the artifact, retaining independent table identities, source ranges, descriptor
digests, GNU build-id/ABI fields and explicit coverage limitations.
Integrate mvanhorn's implementation and hardening with current main while
preserving byte-entropy registration and the Windows curated regression suite.
The maintainer follow-up uses ordinary merges/pushes, not history rewriting.
Executed validation: 96 focused/shared/docs tests, complete static/docs checks,
eleven real CLI/MCP pairs including GCC ELF32 and Clang big-endian PowerPC64,
and two actual Codex task traces checked against their Evidence. Full costs,
grader correction and verification limits are recorded in PR #4837.
Refs #6262.
Construct integer formats directly while preserving bounds, refinements, metadata and current shared schema owners. Keep Incur-dependent CLI numeric coercion declarations unchanged.
Verify canonical advertisements, 126 numeric boundary cases, 974 actual CLI parser cases, broad source tests and real public-artifact SDK workflows. Record 72 normal tasks and 12 separate owned-inspector heap diagnostics with whole-family resource bounds; distinguish SDK spans and asymmetric audit overhead. Generate numerical report sections from receipts and reject stale tables through documentation conformance checks.
Closes#6236. Current-head CI and Greptile pass; actionable review findings are addressed. Codex review was unavailable due repository usage limits.
* feat(native): let callers raise the Apple dispatch metadata input budget
inspect_native_dispatch_metadata refused any Mach-O over a fixed 64 MiB
before decoding, and its recovery said there was no override. Most large
macOS binaries exceed it.
max_input_bytes (CLI --max-input-bytes) now selects the budget, default
64 MiB and at most 1 GiB, through the shared input contract, the enhanced
workflow and the native provider. Results record input_admission with the
effective budget, its source and the retained bytes. A refusal names the
observed size, the budget and its source, and the budget to select or, past
1 GiB, a deep analysis provider.
Fixes#3917
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): describe --max-input-bytes in inspect-native-dispatch-metadata help
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(native): cover max_input_bytes forwarding through CLI and MCP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(native): inspect a universal Mach-O slice in Go and Rust metadata readers
inspect_go_binary and inspect_rust_binary refused universal Mach-O files and
offered no slice selection, so hosts without lipo could not inspect them.
Both now accept architecture (x86, x86_64, arm, arm64). One selector reads
REA's own FAT table, validates the slice range, alignment and header CPU,
and returns the thin image with its macho-selected-image-v1 identity. The
universal file stays the artifact; results add selected_slice and keep
every source range a file offset. Missing, absent, duplicate or misplaced
selections fail on architecture and list the slices present. Subject
format mach-o-universal now has one owner shared by the services and the
retained Go/Rust views.
Fixes#4102
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(native): reject damaged universal files and self-contradicting slice reports
A FAT table whose slice could not be read was treated as a non-universal
file, so callers were told to omit architecture. Its reason now fails on
path. Go and Rust reports with a selected slice must be Mach-O and name the
slice's CPU family, through one shared agreement check. The CLI
architecture flag is described in help.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(engines): keep format ceilings fixed and recover the EVMole deadline
Promote the owned EVMole worker wall clock to timeout_ms and name it in
recovery. Fixed CPU, byte, and address-space refusals in this theme say
the adjustable deadline does not raise them.
Refs #5910
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(engines): recover the allowance that refused the request
Model capacity recovery follows a structured limit instead of message text,
and the shared header ceiling no longer names Safetensors. Firmware signal
errors keep captured tool output, oversized reports do not suggest an
intermittent rerun, and NativeAOT hydration budget exhaustion explains the
fixed parser allowance on the partial report.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): recover macOS command deadlines
Promote native_command_timeout_ms (default 60000), native_ui_deadline_ms
(default 180000), and pwntools_timeout_ms (default 30000) as validated
per-call settings. Keep cpuSeconds, byte allowances, LLDB grace, and plist
probes fixed, and say those caps have no runtime override.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): report the deadline that actually expired
Pass the selected native command timeout through xcrun resolution, thread
the pwntools deadline into pwndbg failures, and state the selected UI
deadline apart from the fixed wait-step cap. SIGXFSZ and EFBIG recovery
names the file-size allowance.
Co-authored-by: morluto <morluto@users.noreply.github.com>
* fix(native): honor the selected deadline on helper stages
The UI helper compile and capture subprocesses used fixed 60s and 30s
exec timeouts, so a longer native_ui_deadline_ms still failed as a generic
provider error. Preparation timeouts reported the 60000 ms default instead
of the selected native_command_timeout_ms.
Memory resource-constraint recovery names memory again, and the Darwin
plist CLI expectation matches the byte-counted input allowance.
Co-authored-by: morluto <morluto@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
fix(errors): derive fixed-allowance recovery from a typed refusal field
inspect_plist refused a binary plist above its fixed 64 MiB decode
estimate, or nested deeper than 128 levels, with resource "memory" and no
recovery, so the shared presentation told the caller to add worker or
host memory. Neither raises that allowance. The 64 MiB source-size refusal
likewise got the worker file-size advice for evidence replies.
AnalysisResourceConstraintError now carries a typed fixedAllowance
{ name, kind }. fixedAllowanceOptions sets it instead of a prebuilt
string, and the presentation derives the recovery from it, so every
existing fixed-allowance producer moves to the same field. Operation
re-attribution, IDA startup re-attribution and explicit redaction copy the
field through one resourceConstraintRecovery helper; redaction still
applies to the allowance name.
The plist decode, nesting and input refusals use the field. A nesting
refusal now reports maximum_nesting_depth instead of the decode byte
limit it did not exceed.
Fixes#5847
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Decode direct Objective-C class names separately from nominal descriptors, retain indirect class bindings as partial facts, and preserve readable protocol and witness evidence when related bytes are unavailable.
Validated with 98 focused tests, check:ci, docs:check, and named-schema CLI/MCP replays of compiler-produced imported-class and struct fixtures plus an inert kind-3 control. The fixtures were inspected statically, never executed.
Fixes#5738
Decode native binary plists from bounded owned source bytes before conversion can erase scalar values. Share scalar preflight and isolate overlapping decoder records while retaining exact integers, date uncertainty, and original bytes. Refuse numeric payloads that read structural table bytes, and avoid retaining projection metadata when callers only need structural validation.
Closes#5701Closes#5703Closes#5705Closes#5782Closes#5783Closes#5792
Remove unsupported DWORD alignment refusals from resource data entries and adjacent directory tables. Preserve original record locations, UTF-16 name alignment, bounds, mapping, overlap checks and payload hashes.
Validation: 49 focused parser/provider/filesystem/lifecycle and compiled CLI/stdio MCP tests; check:ci; independent pefile agreement for the reported layout, padded control and PE32/PE32+ word-aligned directories. Public CLI and SDK-validated MCP retain truncated-input refusals and unchanged source hashes. Synthetic static inspection only; Windows loading was not tested.
Fixes#5750
Move ELF, PE and Mach-O container parsing into a shared native owner. Go alone selects and validates Go build-info sections, so unrelated malformed Go metadata no longer blocks Rust dependency or IL2CPP inspection. Remove the superseded Go-specific container representation and migrate all consumers. Adapted from draft PR #5510 without asserting human PR readiness.
Validation: 51 compiled CLI/MCP acceptance tests across Rust, Go and IL2CPP; 186 shared-reader tests; full check:ci passed. Three public synthetic-file probes reproduce the baseline Rust refusal and validate the fixed SDK-advertised MCP output, artifact digests and unchanged bytes. The exact zero-address nonallocated ELF case now succeeds for Rust while Go still reports invalid_format. No target execution or real compiler-artifact qualification was performed; no performance improvement is claimed.
Closes#3398
Resolve relative pointers using field-owned ABI encodings. Keep null, raw, rebased, imported and unknown targets distinct, and retain imported conformance rows with exact Mach-O binding provenance. Decode legacy rebase membership with source-derived memory and work bounds, preserving validated prefix facts when streams are incomplete.
Validation: check:ci, docs:check and build passed; 158 source tests and 20 schema/acceptance tests passed. Ten source-built Apple dispatch variants and four issue-specific CLI/MCP workflows passed without executing targets. Paired cold/warm CLI/MCP cost observations retained locally; model tokens and maximum-sized input runtime were not measured.
Closes#5683Closes#5685
BREAKING CHANGE: Swift conformance type_name and protocol_name can be null when names cannot be resolved; consumers must use typed type_binding and protocol_binding evidence. MachoImportBinding replaces the former Objective-C-specific binding type and schema.
Count each admitted unique class or metaclass object at its parsing owner. Preserve emitted metadata, independent class-list scan bounds, partial failures, and truncation.
Closes#5706
Count examined and decoded vtable slots in the same population, preserving all returned slots and partial descriptor failures. Document the coverage unit and retain malformed-sibling and unresolved-slot checks.
Closes#5681
Parse only documented compound otool field labels so valid segment and section names are retained at the owning boundary. Verified real Apple clang fixtures through compiled CLI and stdio MCP without executing the targets.
Closes#5680
Tag physical read outcomes at the owning boundary and preserve opaque caller cancellation reasons through JSON pipelines and reference imports. Share named bounded-read options across consumers and retain failed cleanup ownership for retry.
Closes#5686