# 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, Deno, 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 | | `go.build_paths` reads a flag's arguments by the rules of the tool that takes them. A linker `-X` value is an application string, so a relative one is not a path. A rooted one cannot be told from a file path, so it is reported: `-X main.route=/api/v1` is sampled like `-X main.root=/srv/build`, because dropping both would miss the second. `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. The bytes a package member's text or map read returns decide before its name does, so a PE called `payload.js.map` is read as a PE. A header with no NUL byte, or one that starts with a UTF-16 byte order mark, is scanned as text, so names such as `.env.production`, `server.key`, and `credentials` do not depend on an extension list. UTF-16 without a byte order mark has NUL bytes and is not recognized this way. A member already known to be text, such as a script, is also scanned when it is UTF-8 holding a stray NUL. One whose header is at least an eighth NUL bytes is taken to be wide text. It is not decoded and is counted as skipped, as is UTF-32. A binary plist is decoded, so its strings, dictionary keys and data are scanned in whichever encoding each object uses. One that cannot be decoded still has its bytes scanned and is counted as skipped. A file whose header could not be read leaves `text.credential_markers` undecided. A packaged ELF, Mach-O, or PE image is read in full and written to a temporary copy, removed afterward, so it can be probed for an embedded package. All packaged images share one `max_file_bytes` allowance. An image that does not fit, or whose bytes cannot be read, is not probed and leaves member coverage `unknown`. A packaged PE is also read for its debug records. An SVG file is read for its scripts as an HTML file is. A script that an HTML file loads, or a Node SEA main script, is examined as a script whatever it is called, so a name such as `boot.map` does not make it a map, and an HTML file loaded this way is still examined as HTML. Its bytes still decide over that role: a `.map` or loaded script whose text parses as a source map, a JSON object with `version` and `mappings`, `sources`, or `sections`, is read as a source map, so `