Repository navigation
feat(audit): report what a shipped app exposes to static analysis #8525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mvanhorn
wants to merge
173
commits into
morluto:main
Choose a base branch
from
mvanhorn:fix/release-exposure-audit
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+16,859
−65
Open
Changes from 3 commits
Commits
Show all changes
173 commits
Select commit
Hold shift + click to select a range
f183381
feat(audit): report what a shipped app exposes to static analysis
mvanhorn d224dfc
fix(audit): keep incomplete coverage unknown across text, fuses, Go f…
mvanhorn ffc2f23
fix(audit): match package members by source spelling and close remain…
mvanhorn 5cbed6a
fix(release-exposure): bind package members by ordinal and follow nam…
mvanhorn 67c49e9
fix(release-exposure): match data: source map scheme case-insensitively
mvanhorn 3002348
fix(release-exposure): normalize declared map targets and count unrea…
mvanhorn f553459
fix(release-exposure): recover indexed leaves after any map format fa…
mvanhorn a8eefe0
fix(release-exposure): count an unexpanded nested package as a readab…
mvanhorn 1222222
fix(release-exposure): bound the indexed leaf fallback by decoder limits
mvanhorn 169c978
fix(release-exposure): collect UNC roots from Go flag paths
mvanhorn 127be46
fix(release-exposure): keep Electron undecided without positive proof
mvanhorn 81fc997
fix(release-exposure): decode wide text members before scanning
mvanhorn 630352b
fix(release-exposure): follow file: URL source map declarations
mvanhorn 957f25d
fix(release-exposure): match backslash-relative Go flag paths
mvanhorn ec3d2ed
fix(release-exposure): keep fuses unknown on incomplete inventory
mvanhorn cc96be1
fix(release-exposure): decode binary plists before scanning
mvanhorn f31c8c5
fix(release-exposure): keep UTF-8 members that hold a NUL
mvanhorn 12d864b
fix(audit): scan every string a binary plist stores
mvanhorn 9e06282
fix(audit): keep packaged native images from ruling out Electron
mvanhorn 45c45c4
fix(audit): keep readable plist text when one object is unreadable
mvanhorn 19b3380
fix(audit): read escaped inline maps and extensionless SEA entries
mvanhorn 49c9e15
fix(audit): check plist text against the budget before decoding it
mvanhorn bd7e340
fix(audit): count a packaged PE with an unread header as a native image
mvanhorn 2a6415c
fix(audit): keep cleanup-incomplete errors from composed readers
mvanhorn 0981738
fix(audit): keep safe fuses unknown past a packaged native image
mvanhorn cfd9681
fix(audit): settle fuses only on an identified host, and read Bun and…
mvanhorn 2e9eacb
fix(audit): charge map reads to the count before opening the member
mvanhorn 6f0b971
fix(audit): examine scripts HTML loads whatever they are called
mvanhorn a250696
fix(audit): charge sibling map reads to the map count
mvanhorn a765050
fix(audit): report cleanup failures raised by member reads
mvanhorn c4552f1
fix(audit): charge unsuccessful text reads to the byte allowance
mvanhorn 2cec513
fix(audit): bound the paths kept for HTML script targets
mvanhorn a7c705b
fix(audit): keep examining a page loaded as a script as HTML
mvanhorn bdbb070
fix(audit): detect credential markers that end in a hyphen
mvanhorn 8616353
fix(audit): confirm FAT identity for probed package members
mvanhorn 82d2ee4
fix(audit): admit binary plists in package member probes
mvanhorn 2adc01b
fix(audit): locate Go findings only in images that retain build paths
mvanhorn 23fff0a
fix(audit): keep completed findings when member cleanup fails
mvanhorn c50d0ed
fix(audit): keep coverage unknown for nested ASARs in package hosts
mvanhorn 236f2fb
fix(audit): let native format facts outrank member names
mvanhorn ab06b3e
fix(audit): report relative paths given to compiler path flags
mvanhorn 8f019c7
Merge remote-tracking branch 'upstream/main' into fix/release-exposur…
mvanhorn f9eb5e0
test(javascript): expect retained text on SVG inline scripts
mvanhorn fa91268
fix(audit): keep an unresolved Electron host's fuses unknown
mvanhorn 52c801e
fix(audit): bound the paths kept for local source map targets
mvanhorn 5229e5a
fix(audit): borrow the audit's scope admission for inventory
mvanhorn 5b93dab
fix(audit): run the exposure verifier's commands under supervision
mvanhorn e136911
fix(audit): read relative -L paths and split flag arguments
mvanhorn da25b3a
fix(audit): keep embedded leaves beside schema-invalid map fields
mvanhorn 9b34735
fix(audit): keep packaged executables' own packages unknown
mvanhorn d2aa0e0
fix(audit): read an app's sampled images for fuses
mvanhorn a7f3b6a
fix(audit): read a Node shebang as script identity
mvanhorn 39e2794
fix(audit): keep linker strings out of Go build paths
mvanhorn 3d0283d
fix(audit): keep a failed probe directory removal owned
mvanhorn a1919fe
fix(audit): keep a declared .map from reading as a linker map
mvanhorn ffbba64
test(audit): rethrow typed errors from release exposure checks
mvanhorn f9240a6
fix(audit): match companions by member identity, not spelling
mvanhorn 1ccbbf2
fix(audit): retract only guessed linker maps on a declaration
mvanhorn 5673500
fix(audit): record an unfollowed map link as skipped
mvanhorn 130a58c
fix(audit): read relative paths in Go compiler and assembler flags
mvanhorn c5198d0
docs(audit): state the packaged image read allowance
mvanhorn 1753985
docs(audit): say how go.build_paths treats rooted -X values
mvanhorn c0be177
fix(audit): keep a declared sibling map out of the linker guess
mvanhorn a37b652
fix(audit): keep undecodable Go and Rust metadata unknown
mvanhorn b9d8206
fix(audit): keep coverage unknown for a PE header past the probe
mvanhorn 569589a
fix(audit): read the scripts of a standalone SVG
mvanhorn 5d45f63
fix(audit): keep every possible host when no name picks one out
mvanhorn 95e9531
fix(audit): read a text-named native member by its bytes
mvanhorn 9fdb191
fix(audit): let a map or script read identify a native member
mvanhorn 68fe358
fix(audit): name a symlinked sibling debug companion
mvanhorn 1354f58
fix(audit): keep map coverage unknown for a linked script
mvanhorn 03bfcf7
fix(audit): keep a declared JavaScript map beside a selected file unk…
mvanhorn 93beb67
fix(audit): read paths a C compiler forwards to the linker
mvanhorn 5dfcb41
fix(audit): read forwarded linker options by their linker meaning
mvanhorn 4c3d64f
fix(audit): split Go flags as Go does and read external linker flags
mvanhorn 5d8627c
fix(audit): keep a named script beside a selected HTML file unknown
mvanhorn e1710a0
fix(audit): read a retained -pgo setting as one profile path
mvanhorn e10f393
fix(audit): read -extldflags paths as the external linker splits them
mvanhorn ae05674
fix(audit): read the Go linker's other path options
mvanhorn 728be11
fix(audit): keep a quoted Go argument whole
mvanhorn 1d4853f
fix(audit): keep coverage unknown for an unread packaged image
mvanhorn 87af4ef
fix(audit): read rooted Go tool path arguments whole
mvanhorn 3af7940
fix(audit): count an unread packaged member once
mvanhorn da5ecd8
fix(audit): keep trimpath rewrites and directory fields apart from se…
mvanhorn 02cd0e9
fix(audit): keep a .map unsettled once a declaration was discarded
mvanhorn 412f22e
fix(audit): skip env option arguments when reading a Node shebang
mvanhorn 0cb0d43
fix(audit): keep companion coverage unresolved for a generic .map link
mvanhorn 65292aa
fix(audit): count a dropped linker-map guess as a skipped companion
mvanhorn c389586
fix(audit): read env settings after -- in a Node shebang
mvanhorn 279254b
fix(audit): route a selected native image named .map by its format
mvanhorn a44e0e1
fix(audit): read forwarded -rpath and -rpath-link as linker paths
mvanhorn 0afcaea
fix(audit): read each entry of a forwarded linker search list
mvanhorn 198b199
fix(audit): expand loader tokens only in a linker search list
mvanhorn 2cf0df1
fix(audit): count a .map link beside a selected file as a skipped com…
mvanhorn 4241d47
fix(audit): split a linker search list only for an ELF image
mvanhorn a592efd
fix(audit): expand only the image loader's runtime tokens
mvanhorn f8c78d1
fix(audit): keep a declared .map link beside a selected script a sour…
mvanhorn 6d9efe6
fix(audit): byte-check members whose kind is only an inventory path role
mvanhorn 615aef5
fix(audit): read Go's linker -r setting as a runtime search list
mvanhorn 73b0522
fix(audit): keep a selected package executable's native carrier format
mvanhorn 08168e8
fix(audit): keep coverage unknown for an unread unclassified member
mvanhorn 803cd09
Merge upstream/main into fix/release-exposure-audit
mvanhorn 93d3c6d
Merge upstream/main into fix/release-exposure-audit
mvanhorn 81f1063
fix(audit): keep ASAR header admission distinct from max_file_bytes
mvanhorn 85fb7a8
fix(audit): thread the shared ASAR header admission into release expo…
mvanhorn 9468c31
fix(audit): keep a nested ASAR probe stopped at the admission undecided
mvanhorn b2219ee
Merge remote-tracking branch 'upstream/main' into fix/release-exposur…
mvanhorn 8f0b20c
fix(cli): parse audit-release-exposure --max-file-bytes as a decimal …
mvanhorn fb32c96
docs(specs): add the release exposure audit specification
mvanhorn ea87cf8
fix(audit): bind unpacked ASAR member reads to their inventoried digests
mvanhorn 1d3f89f
fix(audit): let stated JavaScript roles outrank a .map name
mvanhorn 10c82f4
fix(audit): keep coverage unknown when a packaged text member fails t…
mvanhorn 8a78bb5
fix(audit): keep the unpacked ASAR digest check inside the read allow…
mvanhorn 3fd85de
fix(audit): read a script target whose bytes are a source map as a map
mvanhorn cf0811a
fix(audit): retract a linker-map guess when a page loads the map as a…
mvanhorn 68657f3
fix(audit): respect script and native identity for sibling linker maps
mvanhorn 7d573ac
fix(audit): read a script-loaded map from the text that recognized it
mvanhorn 6568523
fix(release-exposure): honor byte order marks in binary plist data
mvanhorn 1eaa3f5
fix(audit): keep an unprobed package member past the text allowance u…
mvanhorn bc86750
fix(release-exposure): require a read host for every Electron layout
mvanhorn d3d83a5
fix(release-exposure): keep a .map script past the target allowance u…
mvanhorn 3b473ba
fix(release-exposure): read a Node shebang as script in any text member
mvanhorn dc70c3d
fix(release-exposure): exclude Go search lists by position, not by value
mvanhorn 0cd19ee
fix(release-exposure): keep a probed Node launcher's role past the al…
mvanhorn 3ac3499
fix(release-exposure): decode a map in the encoding its byte order ma…
mvanhorn 4eb9531
fix(release-exposure): keep a lone dash inside a quoted Go path argument
mvanhorn 71de593
fix(release-exposure): choose possible Electron hosts within each layout
mvanhorn 675bf3c
fix(release-exposure): read a relative compiler --sysroot as a build …
mvanhorn 6c18131
fix(release-exposure): recognize Windows Electron layouts by the owne…
mvanhorn 2dba595
fix(release-exposure): read a Bun module by its JavaScript loader
mvanhorn 9ec6e1a
fix(release-exposure): read a Node shebang .map as a script
mvanhorn 7d43921
Detect full-length GitHub refresh tokens
mvanhorn febd305
fix(release-exposure): bind a negative package probe to the inventori…
mvanhorn 36fa4df
fix(release-exposure): let an app bundle read settle only its own layout
mvanhorn 5180f1a
fix(release-exposure): honor a Node shebang before guessing a sibling…
mvanhorn f7f0c03
fix(release-exposure): name a bundle's own layout by the owner's path
mvanhorn 630d4ca
fix(release-exposure): read file-valued linker options as build paths
mvanhorn aa5978f
fix(release-exposure): count a macOS bundle's framework and MacOS hos…
mvanhorn 4924a4a
fix(release-exposure): keep a bundle's launcher out of its fuse hosts
mvanhorn 446b942
fix(release-exposure): keep an undecided PE package member out of lin…
mvanhorn 0f45870
fix(release-exposure): scan the text of an undecided PE map member
mvanhorn f306ad8
fix(release-exposure): keep an oversized text member's undecided PE h…
mvanhorn ed5a475
fix(release-exposure): join Electron layouts by caller path and keep …
mvanhorn b1d9109
fix(release-exposure): keep Electron hosts under a trailing-slash sel…
mvanhorn 18a8851
fix(release-exposure): keep maps unassessed for unread text past the …
mvanhorn aeda62c
fix(release-exposure): keep an unread packaged map member undecided
mvanhorn 66fac02
fix(release-exposure): keep an undecided sibling PE header out of lin…
mvanhorn 1dda8d4
fix(release-exposure): keep possible fuse hosts when no ASAR layout n…
mvanhorn 900f78e
fix(release-exposure): keep images outside a found ASAR layout as pos…
mvanhorn 71a6c9b
fix(release-exposure): keep a dropped host outside a found ASAR layou…
mvanhorn 1eeda3f
fix(release-exposure): read Go build-path response files named in com…
mvanhorn 11ba5de
fix(release-exposure): keep a dropped host outside an ASAR layout unr…
mvanhorn 3b0b5e3
fix(release-exposure): keep maps unassessed for an unreadable extensi…
mvanhorn 931deb5
fix(release-exposure): read a response file named like a dyld token
mvanhorn 580aec3
fix(release-exposure): keep the partial member scan on ordinary cance…
mvanhorn 6820a4c
docs(release-exposure): describe the partial report kept when the mem…
mvanhorn aed8c1a
fix(release-exposure): keep maps unassessed when a text header is cut…
mvanhorn 0e729e7
fix(release-exposure): keep dotted executables as possible hosts in A…
mvanhorn 1e17db2
fix(release-exposure): split env -S shebangs on unquoted blanks only
mvanhorn 41929a0
fix(release-exposure): keep owner facts completed before cancellation
mvanhorn c6a5afb
fix(release-exposure): keep env -S programs named by a variable unass…
mvanhorn 6bf8314
fix(release-exposure): keep the ASAR header admission for selected files
mvanhorn 7bd4927
fix(release-exposure): keep a map member with a variable env -S progr…
mvanhorn f61a72b
fix(release-exposure): read a forwarded -Map linker map path
mvanhorn c5d9afc
fix(release-exposure): count unread text in undecided map branches
mvanhorn 6ac1dee
Merge remote-tracking branch 'origin/main' into HEAD
morluto 15bc3db
fix(audit): bound map reads and preserve linker paths
morluto cdfa3ca
fix(audit): retain unread package uncertainty
morluto 8891afa
fix(audit): retain ambiguous linker operands
morluto 7cf0b69
fix(audit): preserve compiler path separators
morluto c878c1f
fix(audit): retain distinct linker map occurrences
morluto 61af74a
fix(audit): apply map declarations to their exact source path
mvanhorn b77c2eb
fix(audit): keep partial inventory from settling fuse-host coverage
mvanhorn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # Release exposure | ||
|
|
||
| `audit_release_exposure` / `audit-release-exposure` reads one shipped artifact and reports what static analysis of that artifact recovers. The input is a macOS `.app` bundle, an install directory, an ASAR, or a single executable. Each check has a stable id, a status, the observation behind that status, and fixed remediation text. | ||
|
|
||
| The report does not establish that an application is secure. A check that could not be completed is `unknown` or `not_assessed`, and those counts stay beside the findings. There is no pass verdict and no letter grade. | ||
|
|
||
| ```bash | ||
| rea audit-release-exposure /Applications/Example.app --json | ||
| rea audit-release-exposure ./dist/MyApp.app --fail_on high --json | ||
| ``` | ||
|
|
||
| Without `--fail_on`, the exit status reflects only whether the audit finished. With `--fail_on high`, `--fail_on medium`, or `--fail_on low`, a completed audit exits `3` when an `exposed` check meets that severity. `high` matches high. `medium` matches high and medium. `low` matches high, medium, and low. `unknown` and `not_assessed` do not change the exit status. A tool failure is still exit `1`. | ||
|
|
||
| The CLI resolves a relative path against the caller's working directory. MCP requires an absolute filesystem path and returns the same report. MCP has no exit status. | ||
|
|
||
| ```json | ||
| { | ||
| "name": "audit_release_exposure", | ||
| "arguments": { "path": "/Applications/Example.app" } | ||
| } | ||
| ``` | ||
|
|
||
| ## What is read | ||
|
|
||
| The audit composes existing readers. It does not reread Electron fuse bytes itself, and it does not rewrite the artifact. | ||
|
|
||
| | Check | Exposed when | Severity | | ||
| | ------------------------------- | ------------------------------------------------------------------------ | -------- | | ||
| | `javascript.source_map_sources` | A shipped source map has `sourcesContent` | high | | ||
| | `javascript.source_maps` | A shipped source map has no embedded sources | medium | | ||
| | `electron.run_as_node` | The fuse implication is honored | high | | ||
| | `electron.asar_integrity` | Embedded ASAR integrity is not enforced | medium | | ||
| | `electron.only_load_from_asar` | Loading is not restricted to `app.asar` | medium | | ||
| | `electron.node_cli_inspect` | Node CLI inspect arguments are honored | medium | | ||
| | `packaging.extractable_payload` | A Bun, Node SEA, PyInstaller, .NET bundle, or ASAR has a readable member | low | | ||
| | `native.debug_companions` | A `.pdb`, `.dSYM`, `.debug`, or linker `.map` ships beside the release | medium | | ||
| | `native.pdb_path` | A PE CodeView record names a PDB path | low | | ||
| | `go.build_paths` | Go build info or its build flags contain file paths | low | | ||
| | `rust.dependency_metadata` | cargo-auditable metadata is present | low | | ||
| | `text.credential_markers` | A text member contains a provider-prefixed marker | high | | ||
| | `native.hardening` | Not assessed in this audit | | | ||
| | `macho.hardened_runtime` | Not assessed in this audit | | | ||
| | `android.manifest` | Not assessed in this audit | | | ||
|
|
||
| `text.credential_markers` matches provider-prefixed forms such as a PEM private-key header and documented vendor token prefixes. The report contains the rule id and location only. Matched bytes, previews, lengths, and hashes of matched bytes are omitted. | ||
|
|
||
| `native.hardening`, `macho.hardened_runtime`, and `android.manifest` stay `not_assessed`. Their next probes are `inspect_binary_hardening`, `inspect_signature`, and `inspect_android_package`. | ||
|
|
||
| Source map text is counted and then dropped. A selected file is read through the stable artifact reader. Text and source-map members stay inside the allowances listed under `coverage.allowances`, and each kind has its own allowance, so binary members cannot use up the read that a later source map needs. Native images on disk are registered from inventory classification and are not limited to those allowances. Other files and package members are identified from a bounded header. A header with no NUL byte is scanned as text, so names such as `.env.production`, `server.key`, and `credentials` do not depend on an extension list. UTF-16 text has NUL bytes and is not recognized this way. A file whose header could not be read leaves `text.credential_markers` undecided. Among binary package members, only a PE is read further, for its debug records. Skipped members are listed under `coverage.omitted`. When the selection is a file, the parent directory is listed up to a fixed entry allowance for sibling `.pdb`, `.dSYM`, `.debug`, and linker `.map` debug companions. | ||
|
mvanhorn marked this conversation as resolved.
Resolved
|
||
|
|
||
| Inventory stops at 65,536 entries or 2 GiB of hashed bytes, and member coverage then stays `unknown`. A declared integrity value that disagrees with the bytes does not stop the audit, because signing an unpacked native module after packaging is routine. The contradiction is recorded in the limitations and the audit continues. | ||
|
|
||
| A member of a package that inventory did not expand is reported as the host file path followed by the member path, for example `/dist/app.dll/notes.txt`. Inventory-expanded members keep their path relative to the selection. | ||
|
|
||
| A package member skipped by a read allowance still counts as readable for `packaging.extractable_payload`, because the format stores it unencrypted. An encrypted member or one that failed to read counts as unreadable. | ||
|
|
||
| A `.map` too large to parse is a linker map when its header cannot begin a JSON object. A larger `.map` that begins as JSON, or that has a JavaScript name such as `app.js.map`, is counted as skipped. `native.debug_companions` identifies a companion from its name or from a `.map` body that is not a source map, so its `exposed` result has `inferred` confidence. | ||
|
|
||
| ## Status | ||
|
|
||
| `exposed` means the check's condition was observed. `not_observed` means that condition was absent in a completed scan. `not_applicable` means the check does not apply to this artifact, for example Electron fuses on a directory that is not an Electron app. `unknown` means the check could not be decided, including a missing fuse sentinel on an Electron target, a universal binary with a slice that has no sentinel or an undecided fuse, a file that changed after inventory, Electron fuses on a selected ASAR (which does not include the executable that holds them), a PE inside a package that was too large to read, Go or Rust metadata on a native image stored inside a package, and Go or Rust metadata that was not present. Absence of that metadata is not proof the binary is something else. `not_assessed` means this audit did not run the check. | ||
|
|
||
| Cancellation during a Go, Rust, fuse, or desktop read returns a typed cancellation error. Its partial observation holds the report with completed facts, and checks whose readers did not run are `unknown`. Cancellation during the member scan itself returns no partial report. | ||
|
mvanhorn marked this conversation as resolved.
Resolved
|
||
|
|
||
| Severity is `null` unless the status is `exposed`. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.