Commit Graph

2775 Commits

Author SHA1 Message Date
Kaoru0822 46f51ee6cc
fix(flutter): name a missing or non-file APK selection (#2727)
* fix(flutter): name a missing or non-file APK selection

identify_flutter_build and inspect_dart_aot reported a missing path or a
directory as "The APK could not be read as a package: <path>: ENOENT ...",
which blames the package bytes for a selection mistake. Report
"Selected APK does not exist" for ENOENT/ENOTDIR and "Selected APK is not
a regular file" for a non-regular selection, matching the SQLite
inspector's wording. The issue path and invalid_format reason are
unchanged; package format failures keep their existing message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filesystem): classify unopenable non-regular selections at admission

A Unix socket cannot be opened at all: open() fails with ENXIO on Linux
and EOPNOTSUPP on macOS (surfaced by libuv as "Unknown system error
-102") before openRegularFile can stat the descriptor, so such a
selection escaped NonRegularFileReadError and the Flutter provider still
blamed the package bytes.

When open fails, classify the path by its own metadata (lstat when
symlinks are rejected, stat otherwise): an existing non-regular file
becomes NonRegularFileReadError. Missing paths, permission failures,
regular files, and the O_NOFOLLOW ELOOP rejection keep their original
errors. The Flutter selection test now covers a real Unix socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filesystem): reclassify only unopenable file-type errors at admission

Checking the path's metadata after any open failure turned EACCES on an
unreadable directory into NonRegularFileReadError, so callers reported
invalid input instead of access_denied. Reclassify only errors that mean
the file type cannot be opened (ENXIO, EOPNOTSUPP, ENOTSUP, matched by
errno because libuv has no name for macOS EOPNOTSUPP 102); permission,
symlink-rejection and resource failures keep their original errors.

Run the Unix socket selection check in its own test, skipped on Windows
where listen() takes named pipes, and keep the missing-path and
directory checks cross-platform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filesystem): keep cancellation that arrives during the non-regular probe

A caller abort while the post-open metadata probe ran was replaced by
NonRegularFileReadError, so callers such as parseBinaryTarget reported an
input-format error instead of cancellation. Recheck the signal before
substituting the non-regular classification.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:49:23 +08:00
yasshmittal c22d7cd756
fix(browser): keep malformed Content-Length declarations unknown (#2773)
* fix(browser): keep malformed Content-Length declarations unknown

Response metadata normalized Content-Length with Number(), truncation and
clamping, so "-5", "0x10", "1e3" and "+12" became observed lengths 0, 16,
1000 and 12. RFC 9110 section 8.6 defines the field as 1*DIGIT; any other
spelling declares no length. Parse only decimal digits within the safe
integer range and keep every other value null.

Fixes #2596

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(browser): cover the largest accepted Content-Length

Pin the safe-integer boundary beside the overflow case so a future change
cannot reject the largest representable declared length unnoticed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:48:55 +08:00
yasshmittal 4c79127fcb
fix(sqlite): classify a missing database path as an invalid value (#2775)
* fix(sqlite): classify a missing database path as an invalid value

The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.

Fixes #2614

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sqlite): classify a missing database path as an invalid value

The snapshot reported an absent selected database as an artifact path
failure, which the adapter projects as invalid_format alongside malformed
paths and content. The snapshot owns the absence observation, so it now
returns an invalid_value input issue on path directly, matching the
adapter's existing ENOENT/ENOTDIR classification.

Fixes #2614

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:48:39 +08:00
Naimur Reza c8e85b962a
fix(javascript): recover child-process options without args (#2781)
* docs: celebrate 180,000 GitHub stars 🎉

* fix(javascript): recover child-process options without args

* fix(javascript): preserve execFile callback overload options

Choose execFile options by the second argument object shape rather than total argument count, preserving callback overloads.

Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:46:27 +08:00
jbernous fc0dbe7f9d
fix(server): mark retained partial-observation errors as target content (#2398)
Pass the tool contract's `returnsTargetContent` to
`toRecordedPartialErrorToolResult` in the shared Evidence handler, matching
the Electron call site.

The call site that records a retained partial observation was added without
the argument required by the untrusted target-content framing, so the
delivery neither marked the result nor counted the provenance marker in its
wire budget. The type gate failed on main with
`contractToolHandler.ts(69,38): error TS2554`, which also blocked every
compiled boundary test lane.
2026-10-13 21:46:14 +08:00
alfredo1491 23f72141d5
fix(javascript): keep configuration setting reads out of endpoints (#2402)
* fix(javascript): keep configuration setting reads out of endpoints

Static endpoint extraction reads the first literal argument of any call
named get as an HTTP request path unless the receiver is a provable keyed
collection. VS Code extension bundles read settings through
`workspace.getConfiguration(section).get(key)`, so every setting key
became a network endpoint: the bundled Git extension's dist/main.js
reported 173 network endpoints, nearly all of them setting names such as
`autofetchPeriod` and `blame.statusBarItem.enabled`.

The lexical receiver classifier now records a `configuration` fact for a
`.get` call whose receiver is a `getConfiguration(...)` call, inline or
through a binding whose only visible write is one unconditional
initializer. Minifiers emit `let` for these bindings, so the proof relies
on the recorded writes rather than the declaration kind, as tRPC client
root resolution already does. Endpoint extraction skips non-URL literals
for that fact in both application and web bundle analysis. Reassigned,
conditional, and shadowed receivers, URL or path literals, and other
clients such as `api.get("users")` keep their endpoints.

The receiver fact union was duplicated in three modules; consumers now
import the classifier's type.

On the Git extension bundle, network endpoints drop from 173 to 7 with
unchanged analysis time (2.1 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(javascript): require the workspace host for configuration receivers

A bare or differently scoped `getConfiguration(...)` may be an
application's own HTTP client factory, so `.get("users")` on its result
lost its endpoint. Only `workspace.getConfiguration(...)` and
`<x>.workspace.getConfiguration(...)` now produce the configuration fact.
Minifiers keep property names, so the bundled VS Code Git extension still
reports 7 network endpoints instead of 173.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(javascript): recognize default VS Code namespace imports

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:45:07 +08:00
Yann Roberto 5d12a0b4b6
test(web): cover nullable HTTP captures through CDP and CLI (#1834)
* fix(browser): preserve unknown HTTP response comparison fields

* fix(browser): retain proven request inventory changes

* fix(javascript): preserve Electron identity and avoid quadratic property scans

Share visible Electron mutations with wrapper expansion, index static object
literal properties once, and align MCP assertions with current contracts.

* fix(javascript): track writes through symbolic Electron aliases

Resolve mutation targets through the same factories, module tables, containers,
and conditional origins as call analysis. Share mutation coverage between
direct and wrapper scans while isolating origin caches and preserving exact
property paths, local rebinding semantics, and analysis resource limits.

* fix(javascript): preserve container slots and imported mutation origins

* perf(javascript): defer container mutation replay until property reads

* fix(javascript): preserve captured object identities and write order

* fix(javascript): preserve ordered mutation origins

* fix(javascript): honor property mutation constraints

* test(web): narrow PR to HTTP and CLI comparison regressions

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:44:08 +08:00
Ysopwnable 9958754f6c
fix(process): preserve discovery ownership across cleanup retries (#2643)
Bind retained descriptors and runtime resources to their admitting operation until cleanup succeeds, then rebind newly admitted work. Verify failed retries, successful recovery, shutdown and CLI projection.

Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-13 13:43:06 +00:00
BaaRai a4b8e9ccee
feat(ghidra): admit recordless legacy MIPS32 ELFs with a pinned 32-bit language (#1898)
* feat(ghidra): admit recordless legacy MIPS32 ELFs with a pinned 32-bit language

Firmware built with pre-ABI-flags GNU toolchains declares EF_MIPS_ARCH_32
with an unspecified ABI field and no PT_MIPS_ABIFLAGS record. The lane
refused them before provider selection, and Ghidra's own header
auto-selection picks a 64-bit R6 language for exactly these files.

Admit ELF32 ET_EXEC headers with EF_MIPS_ARCH_32 or EF_MIPS_ARCH_32R2,
an unspecified ABI field, EF_MIPS_ABI2 clear and no observed ABI flags
record. o32 is recorded as an inferred analysis assumption
(mips_abi_basis), floating-point ABI semantics stay unverified, and the
existing refusals (FP64, NAN2008, ASEs, machine variants, ELF64) are
unchanged. The profile pins -processor MIPS:<LE|BE>:32:default through a
provider-pinned-v1 selection the bridge-reported language_id is checked
against after import; a caller-selected REA_GHIDRA_LANGUAGE_ID still
wins. The lane identity is versioned
elf32-exec-arch32-legacy-pinned-v1.

verify:ghidra:mips gains a recordless legacy round for both byte orders
that strips the ABI record declarations from a real mips32 fixture,
checks REA's interpretation against GNU readelf, asserts the pinned
language after import and the retained assumption limitations through a
snapshot round-trip.

Fixes #1620

* fix(ghidra): require an inspected absence for the recordless MIPS lane

Address review: undefined ABI flags means the record was not inspected,
not that none exists. Only an inspected absence (null) establishes the
recordless legacy admission; a merely unobserved record keeps its
specific refusal. Also document the legacy admission and its pinned
language in the MIPS provider guide.

* fix(ghidra): tighten the recordless MIPS admission boundaries

Address review: a recordless-looking header whose ABI-record inspection
left declaration sources unexamined (carved ELF with a partial section
table and no program-header record) no longer establishes the recordless
admission; it is refused with the inspection limitation retained. An
EF_MIPS_ARCH_32 header that declares an ABI is refused rather than
relabeled through the 32R2 declared-ABI lane.

* fix(ghidra): reject EF_MIPS_ABI_ON32 from the recordless MIPS lane

Address review: bit 0x40 declares the old n32 ABI. A recordless header
carrying it was admitted with the inferred-o32 assumption even though
the header itself declares n32; the recordless shape now requires the
bit clear and refuses it with a specific constraint.

* fix(ghidra): keep recordless relocatable MIPS objects off the legacy lane

The recordless admission now requires ET_EXEC: the lane and its
verification cover executable firmware images, and a recordless ET_REL
object must stay on the declared-ABI path instead of inheriting the
inferred-o32 assumption under an executable lane id. The ABI-record
requirement paragraph is scoped to the declared-ABI lane so it no longer
contradicts the recordless admission documented above it.

* fix(ghidra): name the ET_EXEC scope for recordless objects and probe the legacy lane

A recordless relocatable object is not an incomplete inspection, so its
refusal now names the ET_EXEC scope of the legacy admission instead of
claiming unavailable ABI headers remain unknown. The recordless legacy
verifier round reads the probe pair and applies the full assertMipsProbe
oracle like the standard round, and its report keeps the independent
GNU readelf receipt beside the fixture facts.

* fix(ghidra): retain the concrete ELF32 legacy compiler pin

* fix(ghidra): bind legacy profiles to fully admitted targets

---------

Co-authored-by: BaaRai <baarai@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:42:38 +08:00
Lluís Ariño c6503edfc4
ci: pin GitHub Actions to full commit SHAs (#1901)
* ci: pin GitHub Actions to full commit SHAs

Replace every third-party `uses: owner/repo@vN` reference in
.github/workflows with the 40-character commit SHA that the tag
currently resolves to, keeping the exact release as a trailing comment.
Each pin was checked with `git ls-remote --tags`: the floating major tag
and the commented release dereference to the same commit. Local
reusable workflows are unchanged.

Re-pin reactivecircus/android-emulator-runner from the SHA of the
annotated `v2` tag object (4c44018e) to the commit it points to
(a421e438, v2.38.0); Actions resolves both, but only the commit SHA is
an immutable reference that tooling can compare with the release.

Update the Windows Ghidra workflow trust-boundary test to require
SHA-pinned setup-node and upload-artifact references instead of the
previous floating tags.

Validation: actionlint v1.7.7 (-shellcheck= -pyflakes=, as in CI), YAML
parse of all workflows, no remaining unpinned third-party `uses:`, and
the workflow boundary/conformance tests.

* style(ci): format action identity assertion

Retain formatting edits produced before the user stopped validation.

Source inspection and git diff --check only. Tests, builds and typechecks skipped by explicit user request. GitHub review writes paused globally.

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:38:46 +08:00
Max 5dd2ce3125
fix(ida): let one-shot commands exit after retaining cleanup (#1841)
* fix(ida): let one-shot commands exit after retaining cleanup

When a headless IDA request outlives timeoutMs (for example idb_open on
a large binary still running auto-analysis), REA cannot prove the
worker stopped and correctly retains the upstream connection and
private workspace. The retained stdio child and its pipes stayed
referenced, so a one-shot CLI printed its cleanup_incomplete result and
then never exited, keeping the supervisor, worker and database alive.

Detach the retained connection's child process and pipes from the event
loop when cleanup fails. A long-lived MCP server can still retry
through the retained connection; a one-shot CLI exits with status 1,
and the supervisor observes end of input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): report an unverified upstream worker after failed cleanup

Upstream ida-pro-mcp spawns headless workers in their own session and
deliberately leaves them running when its supervisor exits, so neither
a retained connection nor REA exiting proves that a timed-out worker
stopped. When cleanup fails before the owned worker's release is
confirmed, the cleanup diagnostics now name its private session and
state that it may still be running until it finishes and reaches its
idle timeout. Failures after a confirmed release, or before any open
was attempted, do not report a worker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): name the inventory sessions that block worker release

When idb_close confirmed the requested worker gone but the follow-up
inventory still found a different peer on the private input, the
upstream_worker diagnostic named the released session and could
misdirect manual cleanup. Record the session ids of the inventory
entries that actually blocked release and report those; fall back to
the requested private session only when no inventory evidence exists
(an incomplete open or an unanswered request). The field becomes
session_ids, since more than one entry can block release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): keep blocker evidence and backend in cleanup diagnostics

The release diagnostic reset its observed blockers on every close, so a
retry whose inventory was unavailable fell back to the already-released
session; and it kept only session ids, describing a blocking GUI
session with detached-worker guidance.

Blocker evidence is now replaced only by a successful inventory, and
the diagnostic becomes upstream_sessions with each session's id and
backend, with guidance that distinguishes workers from GUI sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): stop naming a worker after its close was confirmed

When idb_close confirmed the requested worker's release but the
following inventory failed, no blocker evidence existed yet and the
diagnostic fell back to the confirmed-absent worker. After a confirmed
close the diagnostic now reports an empty session list, meaning any
remaining same-input sessions are unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ida): group cleanup diagnostic cases in their own suite

The added cases pushed the reaped-worker describe block past the
150-line limit enforced by lint:built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): keep ownership and pre-close peers in cleanup diagnostics

Blocking sessions dropped the parsed ownership fact, so an external
unowned worker looked the same as REA's own; and recovery inventory
recorded same-input peers only when the requested worker was missing,
so a peer seen beside it was lost if the following close failed.

Each reported session now carries owned (null when no inventory has
reported it), and recovery records every same-input session until a
later successful inventory replaces that evidence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): drop a confirmed worker from retained cleanup blockers

Recovery inventory now records the requested worker beside any peers,
so once idb_close confirmed its release a failing follow-up inventory
still reported it as unreleased. Remove the confirmed session from the
retained blockers at close confirmation and keep the remaining peers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ida): retry cleanup through a detached stdio connection

The retry coverage used a recording connection whose detach() only
counts calls, so it could not show that detaching keeps a retained
connection usable. Run a real stdio supervisor in a long-lived host,
fail the first post-close inventory, and require the retry through the
same detached connection to confirm release and remove the workspace.
The test fails if detach() destroys the pipes instead of unref-ing them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ida): close the stdio supervisor in failed retry tests

Merge main and give its new IdaNativeProtocol connection double the
required detach() method. The real-stdio retry test now closes its
connection in an unconditional teardown, so a failing assertion cannot
leave the supervisor waiting on stdin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ida): share the cleanup diagnostic expectation in session tests

Repeated upstream_sessions assertions and the unrelated live peer
literal pushed repository duplication over the jscpd threshold. Build
the expected diagnostic with one helper and reuse one peer constant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ida): distinguish observed ownership from unreported input bindings

* fix(ida): keep requested-ID conflicts in recovery cleanup

Recovery inventory kept only same-input entries, unlike the startup and
post-close filters. After an explicitly rejected open, an entry under
the requested session ID on another input was dropped, so cleanup could
close the connection, remove the private workspace and report success
while that session stayed registered. Match the requested ID as well so
the entry is retained as a blocker and cleanup stays incomplete.

Also split the cleanup diagnostics suite under the lint:built function
length limit, and make two startup-inventory fixtures pass a defined
session id so the test file typechecks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Xingchuan Ma <xingchuan.ma@msn.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
2026-10-13 21:36:52 +08:00
Jose Camargo 811bd9f635
docs(contributing): explain Windows native prerequisites for source checkouts (#2295) 2026-10-13 21:34:59 +08:00
Danish Rafie Ekaputra 9e019ad27d
feat(clients): register Factory Droid during setup (#2309) 2026-10-13 21:34:38 +08:00
AICodeLion 117bd23dd5
test(clients): verify Qwen Code on native Windows (#2103)
Co-authored-by: AICodeLion <190163814+AICodeLion@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:27:45 +08:00
Saim Shafique 6637161e02
fix(ghidra): warn when callee/caller reads stop at a truncated function body (#2360)
procedure_callees and procedure_callers returned a bare address list, so an
inferred no-return call that truncates Ghidra's function body silently dropped
real edges (fixes #2326). Wrap both views in the function-observation envelope
with noReturnCallLimitations, matching procedure_info, procedure_assembly,
procedure_pseudo_code, read_function_instructions, and analyze_function
(precedent: 69a8b3a95). Version the boundary-observation contract to
ghidra-terminal-call-limitations-v2 so older snapshots cannot replay
unqualified results.

Validation: red->green unit test for the envelope requirement, MCP boundary
evidence test extended for both views (limitations retained through Evidence
and snapshot replay), 8 harness test files + ghidra behavior tests green,
check:fast, docs:check, verify:test-discovery green. Real Ghidra host lane
unavailable here (no Ghidra installed); Java change mirrors the existing
procedureInfo call pattern.
2026-10-13 21:26:57 +08:00
To3akaRin dea770d5d9
fix(javascript): retain getter receivers through local aliases (#2778)
* fix(javascript): retain getter receivers through local aliases

* fix(javascript): resolve projected private getter receivers

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:26:13 +08:00
Joshwong1908 48b92e1be1
fix(go): classify JVM class files instead of universal Mach-O for CAFEBABE bytes (#2458)
* test(go): pin JVM class files as unsupported Go images

The regression fails on main: readGoBinaryImage(javaClassFile()) reports
"Universal/fat Mach-O containers require selecting a thin slice" for a
JVM class file whose bytes 4..7 are minor/major version, not nfat_arch.

* fix(go): classify JVM class files instead of universal Mach-O

Route the four FAT magics through the shared readFatContainerHeader and
classifyFatContainerIdentity facts added for the same disambiguation in
the artifact and target lanes (921bb9575). Keep the thin-slice failure
only when the container identity is confirmed Mach-O; a JVM class file
now falls through to the generic only-ELF/PE/thin-Mach-O failure.

* test(go): pin universal Mach-O thin-slice failure with FAT fixtures

Cover the kept behavior with the repository's own fatImage/machoImage
builders (narrow and FAT64 tables) so the regression also proves real
universal containers keep the slice-selection failure.

* test(go): cover little-endian FAT magics in the universal container control

* fix(go): require positive universal Mach-O identity

Require positive Mach-O identity before reporting a universal thin-slice remedy; malformed FAT-shaped bytes are not proof. Add the JVM constant-pool CPU lookalike to the existing fixture control.

Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.

* fix(go): retain malformed FAT header diagnostics

Preserve the owning FAT header parser reason for malformed headers while requiring positive Mach-O proof before the universal-slice remedy.

Source inspection and git diff --check only. Tests, builds and typechecks skipped by explicit user request. GitHub review writes paused globally.

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:25:32 +08:00
Luis 003707f712
fix(verification): align Linux Hopper setup lane with current contracts (#1942)
* fix(verification): align Linux Hopper setup lane with current contracts

* fix(verification): retain orphan checks on clean Linux runners

* fix(verification): detect Hopper through alternate launcher paths

* fix(verification): report identified Hopper leaks before proc errors

* fix(verification): distinguish Hopper string recognition from byte fidelity

* fix(verification): report full literal decoding coverage explicitly

* test(verification): require a clean host before orphan checks

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:24:40 +08:00
Jin dd4bfed614
fix(javascript): keep ASAR-named files without an ASAR header opaque (#2347)
Inventory expands an ASAR-named filesystem file only when its bytes are
an ASAR. JavaScript reconstruction expanded it on the suffix alone, so
a directory holding any other file named *.asar failed the whole
analysis with an invalid ASAR header.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:23:58 +08:00
xingzhou 84ec40f1af
fix(browser): distinguish SVG links from HTML XLink attributes (#2480)
* fix(browser): respect SVG desc and title HTML integration points

* fix(browser): preserve moved SVG XLink destinations

* fix(browser): bound concurrent SVG identity reads
2026-10-13 21:23:33 +08:00
Mason 5eb296649d
fix(native): refuse inspect_signature on non-Mach-O targets (#2262)
* fix(native): refuse inspect_signature on non-Mach-O targets

This provider's signature inspection covers Mach-O code signatures only.
On a xar pkg, codesign's "code object is not signed" verdict cannot see
the archive-level signature layer, so a signed or invalidly-signed package
was reported as signed:false with "Artifact is not signed." Match the
existing inspect_macho/list_architectures gate and report
capability_unavailable instead of an unsigned claim for a layer that was
never evaluated.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(native): scope the signature-gate comment to this provider

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(native): align signature capability discovery with Mach-O support

Bind inspect_signature availability to Mach-O targets in capability discovery and align the public tool description.

Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:22:42 +08:00
吴佳浩Alben cae7620b77
fix(apple): report a recognized connector that cannot name its owner (#2484)
* fix(apple): report a connector that cannot name its owner as an omission

A connector is recognized by class name and then dropped by an early
`continue` when its owner cannot be resolved. Nothing recorded the drop, so
connection coverage derived `complete` with `examined: 0` and `omitted: 0`
for a connector that was present, recognized and discarded.

Both producers of that coverage contract are affected and are changed
together, because they share the facet and the reason value:

- the keyed-archive parser records the drop as `unresolvedConnections` and
  reports it through the `connections:<path>` facet, the document
  `connection_count` and the graph omission total;
- the NIBArchive projection in the artifact adapter recorded nothing at all,
  and the projected dictionary carried no trace of the dropped connector for
  a downstream consumer to find. Its count is taken where the connector is
  discarded and plumbed through the same per-document omission channel that
  already carries incomplete hierarchies, so the reason follows the cause.

An unresolved source cannot be represented as a connection at all, because
connection identity requires a non-empty source; that is unlike an unresolved
destination, which the graph already retains as an unresolved edge.
`connection_limit_reached` stays reserved for connections dropped by the hard
cap and `serialized_view_hierarchy_incomplete` for hierarchy omissions.

`connection_count` also includes the unresolved connectors. That field already
counts connectors the parser recognized but could not emit, because
connections dropped by the hard cap are counted there too, so unresolved
connectors follow the existing rule rather than a new one.

Verified with 98 focused Interface Builder and catalog tests, check:fast and
verify:test-discovery on macOS arm64, and through the public CLI: a rooted
archive holding one ownerless UIRuntimeOutletConnection reported complete with
examined 0 and omitted 0 before this change and reports partial with the reason
connection_unresolved and omitted 1 after it.

* fix(apple): count ownerless NIBArchive connectors and keep the limit reason

Greptile found two defects in the NIBArchive half of this change.

The document summary was left unchanged, so the same recognized connector
counted as one in a keyed archive and zero in a NIBArchive. The dictionary
parser only sees connectors that were projected, so the omission recorded
where the connector was dropped is added to the matching document here.

The facet reason was overwritten unconditionally, so a NIBArchive holding both
a connection dropped by the limit and an ownerless connector reported
connection_unresolved and lost the cause a higher limit could recover. The
existing reason is kept when the graph already named one, which is the
precedence the keyed-archive producer applies.

Verified with `npm run test:focused` over the bundle suite (42 passed, 1
skipped), `npm run lint` (0 errors) and `npm run check:fast` on macOS arm64.
Reverting the reason precedence alone fails only the limit case; reverting the
document count fails the count assertion in both cases.

The new case moved into its own describe block because the enclosing callback
crossed the repository's max-lines-per-function bound otherwise.

---------

Co-authored-by: 吴佳浩 <wujiahao@supremind.com>
2026-10-13 21:19:17 +08:00
The one -Niu c44d17fd3c
fix(pwntools): let callers widen the artifact input bound (#2486)
* fix(pwntools): let callers widen the artifact input bound

The pwntools adapters rejected every artifact over 32 MiB before any
analysis ran, and nothing in configuration, environment, CLI or MCP
could raise that bound, so real recorded core dumps stayed unanalyzable.

Resolve the bound from REA_PWNTOOLS_MAX_INPUT_BYTES in front of the
shipped default. An absent value keeps 32 MiB, and a value outside
1..1073741824 bytes is refused as unusable provider configuration before
the artifact is read instead of falling back silently.

* fix(pwntools): name the bound variable in its own refusal

An unusable REA_PWNTOOLS_MAX_INPUT_BYTES travelled through the shared
engine-absence helper, which always stamped configuration_key
REA_PWNTOOLS_PYTHON, so a caller following that field was pointed at the
Python executable instead of the bound it had just set. The guide also
described the refusal as an invalid request while the decoder reports
provider_unavailable.

Let the failure context carry the key under review and pass the bound's
own name at that call site, then state the code callers actually receive
in the guide. Assert the key on the projected rejection so the engine
default and the bound override each stay attributed to the right setting.

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:18:12 +08:00
FengCi 59d33a2733
fix(native): keep lipo path echoes out of FAT records (#2605)
* fix(native): keep lipo path echoes out of FAT records

Parse FAT records only after separating the exact echoed operand path. Pass the same lipo operand at all three consumers and cover multiline paths through parser, slice-reader and compiled CLI regressions.

* fix(native): use parsed lipo framing for container offsets

* test(native): use explicit FAT fixtures for CLI regressions
2026-10-13 21:16:49 +08:00
Kaoru0822 11268fe241
perf(artifacts): share sealed inventory and report in inspect_artifact (#2690)
inspect_artifact parsed a fresh inventory and inspection report but left
both mutable, so each later Evidence boundary cloned and re-digested the
complete payload: createArtifactInspection re-authenticated the nested
inventory Evidence, createAnalysisExecution re-parsed the report, and
recordEvidence re-authenticated the outer Evidence.

Seal both exclusively owned values with freezeJsonSnapshot so those
boundaries take the existing immutable-snapshot path. Output is
byte-identical.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:16:29 +08:00
Angelo Perez e46bed73f1
fix(managed): decode the CIL no. prefix (#2241)
The CIL opcode table held five of the six ECMA-335 prefix opcodes and
omitted no. (FE 19 <unsigned int8>, III.2.2). A method body using it was
reported as malformed with "Unsupported CIL opcode 0xfe19", losing its
instruction counts and normalized IL digest.

Decode it with its one-byte check mask and treat it as a prefix, so it
shares an instruction boundary with the opcode it modifies.


Claude-Session: https://claude.ai/code/session_012pRGskbPGjT444CgJfuhhj

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 21:16:00 +08:00
xin zhuang ece15ed6a1
fix(electron): identify each unresolved scenario path (#2279)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:15:33 +08:00
Kaoru0822 97dc6581f4
fix(dotnet): name the instruction when a CIL operand leaves the method body (#2697)
The decoder already reports "Instruction X at IL offset N leaves method
body" when an operand's computed end passes the IL body, but only after
the operand was read. Operand readers use Buffer reads, so an operand
cut off by the body end threw a RangeError first. The catch-all stored
Node's message ("Attempt to access memory outside buffer bounds" or an
offset RangeError) as body.issue, dropping the instruction and offset.
A body ending in a lone 0xFE two-byte opcode prefix failed the same way.

Treat a RangeError from the operand read as the operand leaving the body
so the existing diagnostic applies, and check the second opcode byte
before reading it. Malformed status, partial coverage and earlier
decoded instructions are unchanged.

Fixes #2677

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 06:14:31 -07:00
TonyWu cdc41fc86c
fix(managed): classify ReadyToRun images without ILONLY as modern .NET (#2075)
* fix(managed): classify ReadyToRun images without ILONLY as modern .NET

crossgen2 clears COMIMAGE_FLAGS_ILONLY and sets IL_LIBRARY on ReadyToRun output. inspect_managed_artifact checked the clear ILONLY flag before the ReadyToRun signature, so real ReadyToRun assemblies were reported as runtime_family mixed-clr-native and implementation cpp-cli-mixed, and cil-and-ready-to-run was unreachable for crossgen2 output. Check the ReadyToRun signature first; a clear ILONLY flag without it still reports mixed CLR/native code.

* test(managed): exhaust capacity through inspected assembly references

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:13:18 +08:00
记得吃中饭 9c14999efd
feat(ghidra): support raw NMOS 6502 analysis (#2079)
* feat(ghidra): admit raw NMOS 6502 analysis

* test(ghidra): require verified POSIX verifier cleanup

* test(ghidra): verify 6502 low-memory raw imports

* docs(skill): document raw NMOS 6502 support

* fix(ghidra): preserve requested Windows raw source paths

* docs(ghidra): include raw 6502 in Windows installation scope

* test(ghidra): verify Windows raw junction rejection through CLI and MCP

* fix(validation): make fixtures portable and preserve explicit Codex home

* fix(ghidra): attest raw mapping state and address space

* fix(ghidra): align diagnostics and regression groups

* fix(ghidra): bind raw attestation to language address space

* chore(ghidra): avoid verifier insertion conflict

* docs(ghidra): align linked raw admission guides

* fix(ghidra): retain 6502 verifier workspace on failure

* test(ghidra): isolate Windows authority doctor fixture

* fix(binary): re-admit Windows raw paths on session reopen

* test(binary): require fresh provider execution after path change

* Constrain 6502 to raw lifecycle and snapshot targets

* Bypass saved reads for unadmitted Windows paths

* Guard direct CLI snapshot replay on Windows paths

* fix(snapshot): gate Windows Ghidra replay on native admission

* fix(snapshot): constrain nested 6502 subjects to raw images

* test: make dyld slice fixtures portable
2026-10-13 21:13:01 +08:00
Aravind Rao 352c46aa75
fix(javascript): keep CommonJS require file URLs unresolved (#2077)
* fix(javascript): keep CommonJS require file URLs unresolved

require("file:///dep.cjs") was reported as a resolved dependency of
the inventoried dep.cjs although Node rejects the string with
MODULE_NOT_FOUND. The shared module-specifier resolver decoded file URLs
before the declared CommonJS loader semantics.

File-URL decoding now applies only to non-require module specifiers, so a
CommonJS file URL reports external with its declared string and source
evidence preserved. ESM file URLs and ordinary relative require paths
keep their established lookup.

* test(javascript): consolidate CommonJS file URL public workflow coverage

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:12:50 +08:00
Nelglor 91830f1e0e
feat(managed): name the declaring type of call and field targets (#2163)
* feat(managed): name the declaring type of call and field targets

Call edges named external targets by member name alone (Join, ToJson,
WriteAllText), and method-spec edges had no name at all, so an analyst could
not tell which library a method calls or find every use of a type without a
decompiler. Field accesses through MemberRefs had no name either.

Name each TypeDef, TypeRef, and generic-instantiation TypeSpec once, in the
namespace-qualified form TypeDef full_name uses, and add member_refs
parent_name, call_edges target_declaring_type, and field_accesses
field_declaring_type. A method-spec target reports the generic method it
instantiates. Fields, member references, methods, and method specs now
resolve through one token-keyed MemberCore lookup instead of three maps.
Evidence recorded before these fields reads them as null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate spec blobs and member kinds before naming targets

Address review findings on declaring-type naming:

- A generic instantiation must name a TypeDef or TypeRef, so a TypeSpec
  base is reported as malformed instead of followed. Naming no longer
  recurses.
- TypeSpec and MethodSpec instantiation blobs are decoded with the
  member-signature grammar. Malformed blobs and out-of-range TypeDef rows
  are reported against their owning row and make coverage partial.
- A MethodSpec reads both columns. An invalid Method coded index is
  reported; a readable Method keeps its name beside a malformed
  instantiation.
- MemberCore carries its signature kind, so a field operand is named only
  by a field or field-signature MemberRef. This replaces the token-table
  guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate MethodSpec arity and report unsupported spec blobs

- A MethodSpec now checks that its method signature is generic and that
  the instantiation supplies as many type arguments as it declares. A
  non-generic target, a field reference, or a count mismatch is reported
  as invalid-row; the readable method keeps its name.
- Unsupported TypeSpec and MethodSpec forms raise an owner-scoped
  unsupported-signature issue instead of reading as an intentional
  unknown.
- MethodSpec reading moves to ManagedMethodSpecs.ts, and its tests get
  their own describe block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): reject non-method signature headers and invalid TypeRef scopes

The method signature header reader now owns the calling-convention rule
that only FNPTR applied: FIELD, LOCAL_SIG, PROPERTY, and GENERICINST
headers, the reserved bit, and EXPLICITTHIS without HASTHIS are malformed.
A MethodSpec whose method has a PROPERTY header is no longer accepted as a
generic method, and member signatures with such headers no longer decode
as methods.

The type-name lookup validates a TypeRef's ResolutionScope coded index and
reports an out-of-range scope as invalid-row, keeping the readable name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): hold member rows to MethodDefSig and FieldSig headers

Method signature headers are now checked in context. MethodDef and
MemberRef rows accept only the MethodDefSig/MethodRefSig headers: DEFAULT,
VARARG, or GENERIC with DEFAULT. FNPTR keeps the unmanaged conventions
compilers emit for function pointers. A field signature must be exactly
FIELD, so a flagged FIELD header is malformed and never names a field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): accept MethodSpec arity only from a fully decoded signature

The arity check read only the target's signature header, so a truncated
generic method signature passed. Under type selection a MethodDef target
outside the selection is never decoded elsewhere, so coverage stayed
complete. The arity now comes from a transient full decode, and only a
decoded method signature supplies it. signature() keeps its raw length
and digest around the shared decodeSignature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(managed): decode each MethodSpec target signature once

edgeTargets caches the generic arity, including a failed decode, by
target method token, so many instantiations of one generic method share
a single signature decode. Unity.InputSystem has 472 distinct MethodSpecs
over about 133 target methods.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): validate spec type operands and transitive reference scopes

* fix(managed): retain readable names when a scope row is unreadable

* test(managed): pin owner-scoped spec operand and scope-chain checks

e59217c83 validates spec type operands inside specSignature, so a
malformed generic TypeSpec base is now invalid-row under its owning
TypeSpec row; the three stale expectations follow that. New cases cover
a TypeSpec argument and a MethodSpec argument that name a missing TypeRef,
and a TypeRef whose ResolutionScope names itself. The scope cases move to
their own describe block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): keep field targets from naming MethodSpecs

A MethodSpec over a field-signature MemberRef inherited kind "field", so
an ldsfld on that MethodSpec published a field name and declaring type
for malformed IL. A MethodSpec now borrows its target's name only when
the target is not a field; the arity check still reports it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): reuse owner-decoded signatures for MethodSpec arity

MemberRef signatures, and MethodDef signatures in the type selection, are
already fully decoded, but the MethodSpec arity check decoded them again
and admitted a second transient allocation, which could exhaust the
budget. MemberCore now carries the owner's genericArity, and only a target
nothing decoded, such as an unselected MethodDef, falls back to the raw
signature. signatureGenericArity is the one rule for both paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:12:15 +08:00
Luis Araya df04f99df0
fix(readiness): deduplicate stage-level missing-evidence findings (#2203)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:10:56 +08:00
yasshmittal d2e16b2a49
fix(sqlite): attribute unknown column selections to columns (#2774)
Every worker "selection" rejection was projected onto the table argument,
including an exact column name that does not exist in an existing table.
Give column rejections their own worker reason and map each input reason
to the caller argument it requires correcting. Table rejections keep the
table path.

Fixes #2613

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:03:14 +08:00
Aliciawque 928b4d5fe4
fix(plist): decode formatted XML dictionary keys (#1843)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:59:02 +08:00
jhuang-tw 4ea24f9767
fix(ida): retain private input after ambiguous open (#1845)
fix(ida): retain private input after unverified open
2026-10-13 20:58:51 +08:00
Jin 2a61deafc6
fix(adb): report the device state when a push cannot probe the path (#2354)
A push without overwrite read any unclassified failure of its existence
probe as an existing path, so an offline or unauthorized device was
reported as "the device path already exists". With overwrite it pushed
after a probe that had not established anything. The probe's own
refusal is now returned in both cases.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:56:41 +08:00
Mykola Dementiev 5f8af4ee5f
feat(ida): resolve containing procedures and report the admitted program as the document (#2374)
* test(mcp): expect trace_feature to report references the provider truncated

A provider that reports a capped xrefs read makes the trace truncated with a residual unknown for that target. An explicit complete report and a provider that reports nothing leave the trace as before.

* fix(mcp): report references a provider truncated in trace_feature

Executions gain an optional flag for a capped xrefs read, set by the IDA adapter from the upstream cap. trace_feature marks the trace truncated with a residual unknown for that target only when the provider reports a truncation; a provider that reports nothing keeps its previous result. The trace_feature workflow profile is revised so earlier results are not replayed.

* refactor(ida): report reference truncation whenever the runner observed an xrefs cap

* test(mcp): cover session forwarding, per-target state, native reports and failures of the trace coverage

* test(mcp): format the session forwarding test

* test(ida): expect headless IDA to resolve containing procedures from lookups and segment facts

Cover positive and negative containment, segment boundaries including addresses above 2^53, failures of the lookup and of the segment survey, cancellation, input validation and the admitted program as the only document.

* test(ida): expect feature tracing and address context to work on headless IDA

Run trace_feature, including a capped reference read, and inspect_address_context with and without an explicit document through the IDA session client.

* test(mcp): expect trace_feature availability to follow the search operations it calls

* fix(mcp): derive trace_feature availability from the search operations it calls

* feat(ida): resolve containing procedures and report the admitted program as the document

The modern headless profile resolves an address through the function lookup and, when no function contains it, tells a mapped address from an unmapped one using the database-scoped minimal survey. A survey that is missing, truncated or inconsistent fails the read. list_documents reports the single admitted program. The attached profiles do not declare either operation.

* docs(ida): describe containing procedures, the admitted document and truncated feature traces

* test(ida): verify containing procedures, the admitted document and feature tracing on real IDA

* docs(testing): list the headless IDA workflows the real lane verifies

* test(ida): make each survey failure case isolate a single defect

* test(ida): pin large addresses, segment order, document identity, attached refusals and each trace_feature prerequisite

* test(mcp): expect a repeated reference source to be resolved once in trace_feature

* fix(mcp): resolve the containing procedure of a repeated reference source once

* test(ida): trace the fixture procedure and derive probe addresses from its facts in the real lane

* test(process): format processCaptureLifecycle.test.ts after the merge

* test(ida): declare the alignment each synthetic universal slice offset satisfies

* refactor(ida): move the real lane's feature trace assertions into a helper

* test(ida): expect the real lane's feature trace check to accept references to every matched address

* fix(ida): check each trace reference against its own matched address in the real lane

* test(ida): pin that the new operations reject a document other than the admitted program

* refactor(ida): move the real lane's mapped non-function probe into a helper

* test(ida): expect the real lane's mapped data probe to skip strings inside functions

* fix(ida): try the target's strings in order for the mapped non-function probe

* test(ida): declare the real lane helper types for the verifier tests

* test(ida): expect the real lane to reject a listed string that resolves as unmapped

* fix(ida): fail the real lane when a listed string resolves as unmapped
2026-10-13 20:56:20 +08:00
Dery Ferdika e0bd31c18c
fix(ghidra): bound the Java version probe output (#2361)
The Java version probe captured its output with maxBuffer set to Infinity, so a
chatty or hostile JVM selected as the Ghidra launcher could grow the captured
stdout/stderr without limit and exhaust REA's memory during installation
discovery. Bound the capture to 1 MiB, matching the budget already used for
other Java listings. A probe that exceeds the budget yields no observation and
is reported through the existing failed-probe path, the same one the Java check
already uses whenever the probe cannot produce an observation.

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-10-13 20:55:40 +08:00
Lucas LSMO 8e6f37e2a0
fix(formats): preserve high bits in remaining magic-byte checks (#2384)
* fix(formats): preserve high bits in remaining magic-byte checks

Node's "ascii" decoder masks the high bit, so byte-for-byte signature
comparisons accepted lookalikes such as CD DA ("MZ" | 0x80) or a
high-bit "bplist00"/"NIBArchive" header. ac57c88ef fixed this for the
shared DOS/MZ reader; apply the same latin1 decoding to the remaining
signature checks: NativeAOT and Windows native loader MZ/PE, binary
plist and NIBArchive detection, and PNG IHDR checks.

Display-name decodes (section and metadata stream names) are unchanged.

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

* style(windows): format signature admission regressions

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:54:37 +08:00
Aurantium 43738bec57
fix(targets): retain unsupported PE machine in diagnostics (#2448)
Assisted-by: OpenAI GPT-6 <noreply@openai.com>

Co-authored-by: Aurantium-47 <280805072+Aurantium-47@users.noreply.github.com>
2026-10-13 20:52:17 +08:00
Rudy Mizrahi Celekli 03ab521db3
fix(process): resolve POSIX backslash basenames through PATH (#2471)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:51:44 +08:00
AbdulAzizWang 0ca70e121c
fix(ghidra): pre-create the launch-support config directory (#2470)
* fix(ghidra): pre-create the launch-support config directory

Ghidra's launch support resolves its JDK before the headless run starts and
persists that choice under `<config>/ghidra/<release directory>`. Inside REA's
private runtime a child JVM cannot create those directories, so the first
Windows Ghidra query aborted at ghidra.launch.AppConfig.saveJavaHome with:

    java.io.IOException: Failed to create directory:
    ...\config\ghidra\ghidra_12.1.4_PUBLIC
        at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145)
        at LaunchSupport.findJavaHome(LaunchSupport.java:210)

LaunchSupport then fell back to its interactive prompt, read EOF, and reported
"JDK 21+ (64-bit) could not be found and must be manually chosen!", so the
provider failed with "Ghidra exited before bridge startup" even though
`rea doctor` reported a valid Ghidra installation and JDK.

Create the release directory while this process still owns the runtime, leaving
Ghidra only a file write inside it. The release coordinate comes from the
installation's Ghidra/application.properties (application.version plus
application.release.name) with the extraction directory name as a fallback. On
Windows each level goes through the native private-runtime owner, which opens
every existing component and creates only the final one.

Verified on Windows x64 with Ghidra 12.1.4, a 64-bit Temurin JDK 21, and REA's
packaged native addon: `rea inspect <x64 PE DLL> --provider ghidra` and the
equivalent MCP `binary_overview` call both complete and report 21 segments,
1436 procedures, and 2761 strings. Windows Ghidra remains read-only P0; this
change does not extend that boundary.

* style(ghidra): format launch configuration regressions

* fix(ghidra): reuse Java Properties parsing for launch release identity

---------

Co-authored-by: AbdulAzizShanShi <441650742@QQ.COM>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:51:18 +08:00
Danish Rafie Ekaputra f63674cac0
docs(browser): clarify attach coverage and Chromium setup (#2287)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:44:41 +08:00
Chaoqi d3a55720fc
fix(setup): keep Hermes config numbers as written (#2368)
Setup and uninstall re-printed every number in an existing Hermes
config.yaml from a JavaScript number. Hermes reads the file as YAML 1.1
with exact integers, so a Discord channel ID lost its low digits, an
octal mode such as 0600 became 600, and 0.0000001 became 1e-7, which
YAML 1.1 does not define as a float. Two IDs that round to the same
double were also rejected as duplicate keys, so setup could not
register at all.

Hermes YAML parsing and editing move to HermesConfigurationYaml. A parsed
number is written with its source spelling while that spelling still
reads as the node's value, the rule yaml's own boolean tag follows, and
two keys are duplicates only when both their value and their spelling
match. Parsed values stay JavaScript numbers.
2026-10-13 20:44:17 +08:00
Jin 36132d3e17
fix(managed): classify 32-bit-preferred assemblies as platform neutral (#2342)
The CLI header's 32BITREQUIRED and 32BITPREFERRED bits are one two-bit
field. Reading 32BITREQUIRED on its own reported Prefer32Bit assemblies
(flags 0x00020003) as x86-only with requires_32bit true, and left
anycpu-prefer-32 reachable only through the reserved combination.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:43:39 +08:00
Jack Liang 1ca5fd38b4
fix(cli)!: keep a selected JSON null in --filter-output output (#2333)
createCliResultOutput rendered an explicit null selected by
--filter-output as the empty document {}, the same output it uses when
the selection has no value at all. On the streamed JSON/JSONL path,
a consumer could not distinguish a selected null from a missing field.

Write a selected null as null in streamed JSON and JSONL. This also
preserves an unfiltered top-level null. The {} fallback stays for
undefined, functions and symbols. The --full-output envelope already
carried data: null for a selected null. The --token-count path still
hands results that fit the formatted-string limit back to Incur and
prints 0 for a selected null. Other formats and Incur-owned result
paths are unchanged.

Consumers must accept JSON null for a present null and distinguish it
from a missing selection. Use --full-output if an object envelope is
required. Keeping the old shared {} representation would continue
hiding this distinction.


Claude-Session: https://claude.ai/code/session_019TTGAv6fe859ebbCLLfLHP

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:43:20 +08:00
Saim Shafique 84cf7791a8
fix(call-path): keep caller-only unknown coverage from blocking not_found (#2371)
* fix(call-path): keep caller-only unknown coverage from blocking not_found

build_call_path expands only callee edges, so relationship coverage that
is unknown solely because callers are unobservable (the modern headless
IDA profile) no longer marks the searched callee closure incomplete.
The caller caveat stays visible in limitations, and callee-side unknowns
still yield unknown. Fixes #2322.

* test(call-path): cover IDA-capped callees beside unknown callers

Greptile review noted the poll-timing coverage only exercised unknown
callees, leaving the partial callees IDA returns at its 500-result cap
untested. Add the combined unknown-callers/partial-callees case:
isCallerOnlyUnknownCoverage must stay false and buildCallPath must keep
search_scope.exhaustive false, so a future change cannot silently report
not_found when IDA has omitted callees.
2026-10-13 20:42:40 +08:00
yasshmittal ec4f4ddc58
fix(ghidra): read UTF-8 signed language definitions (#2772)
Buffer#toString kept a leading UTF-8 byte order mark as U+FEFF, so the
strict XML parser rejected a valid .ldefs file as content outside the root
element and aborted the whole language catalog read. XML 1.0 section 4.3.3
defines the mark as an encoding signature; decode with TextDecoder, which
consumes it. Malformed XML is still rejected.

Fixes #2533

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:41:28 +08:00
Omisakin Joshua 8823c55b0c
feat(ghidra): decode Swift String literals in function dossiers (#2049)
* feat(ghidra): decode Swift String literals in function dossiers

Swift passes a String as two words. Small literals keep their UTF-8 bytes
inside those words, and immortal large literals keep a count plus a pointer
to their bytes biased by 32. Ghidra creates no data reference for either, so
analyze_function reported no strings for Swift code.

On AArch64 programs that contain Swift metadata, the Ghidra bridge now runs
constant propagation over the function and decodes register pairs where
Swift consumes a String: consecutive argument registers at calls and tail
calls, x0 and x1 at returns, and both registers of one STP. Large literals
must resolve to terminated bytes inside one initialized block that is not
executable. A pair whose registers both come from conditional selects is
skipped, because Ghidra forks each select without correlating the
condition and could otherwise pair words from different cases.

Decoded values are a derivation from the ABI layout rather than observed
references, so they appear in a new optional swift_string_literals field
with their source instruction, registers and raw words, and in a matching
inspect_analysis_view facet. referenced_strings is unchanged.

Refs #2030

* fix(ghidra): bound Swift literal reads and compare decoded strings

Large immortal literals are measured against the remaining heap before
allocation, and a failed fit stays visible as a limitation. The canonical
empty string is kept. Small and large literals now require matching
address nullability, and function comparison treats decoded literals as
string evidence without equating a missing record to an empty one.

* fix(ghidra): budget Swift literal decoding and tighten use sites

Large literals now draw on one heap budget per dossier, measured once
before decoding, instead of a separate check per literal. A literal that
does not fit is listed in a new swift_string_literal_omissions field
with its address, byte length and reason, so consumers read omissions
from structured data rather than from limitation text.

strings_names comparison checks referenced strings and names first and
reports a change there even when Swift literal coverage differs; it
returns unknown only when those facts match and literal coverage is
absent on one side or partial.

A computed jump counts as a tail call only when it has no resolved
target inside the function, so jump tables no longer qualify, and a
return requires a RETURN p-code operation, so traps no longer qualify.

Decoded literals keep control characters, which Swift strings may
contain and JSON escapes. The Swift verifier builds the literal fixture
for arm64 on any Mac host and now also covers the empty string and a
literal containing a tab.

* fix(ghidra): charge escaped JSON and follow copied selects

The Swift literal budget now charges the worst case per UTF-8 byte: UTF-16
text, six escaped JSON characters held in Gson's growing buffer and in the
returned String, and the UTF-8 bytes written to the socket. Literals made
of control characters can no longer exceed the reserved heap.

A jump counts as a tail call only when every resolved target lies outside
the function. The conditional select check follows register copies back
to their definition, so selects copied into argument registers are
recognized like selects written there directly.

strings_names reports a change when both dossiers decoded different
literals at the same use site, even when either side has omissions; it
returns unknown only when no such use site disagrees.

* fix(ghidra): bound literal records and trace selects across branches

Every Swift literal record now pays a fixed cost against the dossier
budget in addition to its text, so many empty or small literals are
bounded as well. The first record that does not fit is kept as an
omission and decoding stops there, which keeps the omission record
itself bounded; omissions now describe small or large literals.

The conditional select check searches every predecessor path for the
reaching definitions, following register copies, so selects made
before a branch into the use block are recognized.

A dossier records Swift literals and their omissions together. Coverage
reads omissions first, and strings_names compares every use site that
neither side omitted: a decoded literal is known where it was recorded,
and an absence is known only in a dossier whose decoding examined every
use site.

* fix(ghidra): stop every flow at the literal budget and route omissions

Ending one flow from the evaluator leaves other queued flows running, so
the budget now records a shared stop that every flow checks before it
examines another instruction. A record that exceeds the budget is routed
by that capacity result rather than by whether text was decoded, so a
small literal over budget becomes an omission instead of a literal.

When coverage is partial, the per site comparison keeps each literal's
representation as well as its value, matching the full strings_names
projection.

* fix(ghidra): keep unresolved Swift tail-call sites unknown

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 20:41:10 +08:00