unrea
Scans Electron application builds for exposed secrets, shipped source maps and tests, readable code, and weak Electron fuses; provides hardening and remediation guidance.
Scans .NET builds for readable code and names, shipped PDBs, sensitive names, unsigned binaries, and obfuscation status; provides findings and fix guidance.
Scans Unity Mono/IL2CPP game builds for shipped debug symbols, readable names, plugins, client-authority issues, and save exposure; provides findings and remediation guidance.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@unreascan ./dist for reverse-engineering leaks and explain the high-risk ones"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
unrea β anti reverse engineering scanner for AI-era apps
AI agents like REA can take apart an Electron app, a .NET tool or a Unity game in minutes. unrea shows you what they would find in your build, and your own agent fixes it before you ship.
npx @yigitguldal/unrea scan ./distFinds what leaks: API keys and tokens,
.envfiles, source maps, shipped tests and debug symbols, readable code and names (JS, .NET, Unity Mono), unencrypted Godot exports, unsigned or unhardened executables, weak Electron fuses.Built for agents: an MCP server + skill for Claude Code, Codex and OpenCode. Your agent scans, explains each finding and applies the fix.
Honest: obfuscation only slows attackers down. unrea pushes you toward the fix that holds up: secrets and valuable logic on your server, so a cracked client gets the attacker nothing.
Read-only and offline: it never edits your build and never calls the network. Secrets are masked in every output.
Why
Reverse engineering used to take a skilled person and a weekend. Now an agent with an MCP toolkit unpacks app.asar, greps every string, decompiles your DLLs and writes up the result. "Nobody will bother" doesn't hold anymore. Most leaks are boring: a key in a bundle, a .map file, a test folder nobody excluded. unrea catches them in seconds, while they're still cheap to fix.
Related MCP server: REA
What's covered
Target | Status |
Electron / JavaScript ( | β |
Any build: keys, | β |
Unity (Mono / IL2CPP), Godot export settings, .NET, PyInstaller, Windows PE | β |
Android APK, Flutter, Apple bundles, ELF / Mach-O | π§ next |
Web builds, WASM, shipped databases, recorded traffic | πΊοΈ planned |
The goal is to cover everything REA can analyze, with a defender module for each. See ROADMAP.md.
Use it from your AI agent
npx @yigitguldal/unrea setup --client claude_code # prints the claude mcp add command + copies the skill
npx @yigitguldal/unrea setup --client codex # merges ~/.codex/config.toml
npx @yigitguldal/unrea setup --client opencode # merges ~/.config/opencode/opencode.jsonAdd --dry-run to see every write first, or --json for machine-readable
output. UNREA_HOME overrides the home directory (useful for tests and
sandboxes).
Where it writes:
Client | MCP registration | Skill |
| Prints |
|
|
|
|
|
|
|
The setup merge is idempotent and skips an existing unrea entry. Restart the client afterwards. For Claude Code, run the printed command once.
Then ask your agent:
scan my build with unrea and fix everything highThe agent works this loop:
build -> unrea_scan -> unrea_explain -> unrea_fix_plan -> apply -> rescanStop when there are no high or critical findings.
MCP tools
Tool | What it does |
|
|
|
|
|
|
|
|
unrea_scan honors min_severity and max_findings for the findings array;
summary, grade and top_fixes always describe the full scan. Secrets stay
masked in MCP JSON, just like --json. Accepted findings keep
accepted: true and reason, and the payload reports how many were accepted.
The skill is bundled at skill/unrea/SKILL.md; it tells the agent the rules to
follow while writing code and the release loop above.
CLI
npx @yigitguldal/unrea scan ./dist
npx @yigitguldal/unrea scan ./dist/win-unpacked --json
npx @yigitguldal/unrea scan ./MyApp/resources/app.asar --verbose --fail-on critical
npx @yigitguldal/unrea mcp # stdio MCP server (normally launched by the client)Options:
Option | Meaning |
| Machine-readable output (always complete; includes |
| List every finding in text mode (no collapsing or 5-row cap) |
| Force source-repo mode: skip |
| Force build mode even if the folder looks like a source repo |
| Exit 1 when a finding reaches this level (default |
| Accept list file (default: |
| Write a SARIF 2.1.0 report for GitHub code scanning |
| Write a shields.io endpoint JSON badge |
| Write a GitHub job summary; appends to |
Exit codes: 0 clean (or below threshold), 1 threshold reached, 2 bad
usage or unreadable path. Secrets are always masked in text and JSON output.
If the target looks like a source repo (package.json plus src/, test/ or
.git, with no build artifact at the root), unrea warns you to scan the build
output instead. In that mode it skips node_modules and does not emit
tests.shipped. Force it with --source, or disable detection with --build.
Sample output
unrea 0.4.0 - client exposure scan
target: dist
surfaces: electron, generic
files scanned: 664
duration: 812 ms
grade: F (1 critical)
CRITICAL (1)
CRITICAL resources/app.asar!/main.js:12 OpenAI key: sk-pβ¦6X
fix: revoke and rotate this OpenAI key; call the API from your server
HIGH (2)
HIGH resources/app.asar 14 test files ship in the build (e.g. resources/app.asar!/test/x.test.mjs)
fix: exclude test folders from the package (electron-builder `files` / .npmignore)
HIGH app.exe RunAsNode: enabled
fix: RunAsNode is enabled: flip it with @electron/fuses at build time
MEDIUM (1)
MEDIUM resources/app.asar!/app.js.map:1 app.js.map shipped in the build
fix: disable source maps in production build
INFO (458)
INFO endpoint.internal x458 (e.g. resources/app.asar!/main.js:88)
Summary
critical: 1, high: 2, medium: 1, info: 458
top fixes to do first:
1. revoke and rotate this OpenAI key; call the API from your server
2. exclude test folders from the package (electron-builder `files` / .npmignore)
3. RunAsNode is enabled: flip it with @electron/fuses at build timeText mode collapses info rows to one line per id and shows at most five
findings per id/severity. --verbose lists them all; --json always contains
every finding.
Grade: A nothing medium or worse, B up to 3 medium, C more than 3 medium, D any high, F any critical.
What it checks
ID | Severity | What it means |
| critical / high / info | Live provider keys (AWS, OpenAI, Anthropic, Stripe, GitHub, Google, Slack, PEM), Supabase JWT roles, high-entropy literals assigned to secret-looking names. Masked in output. Secrets in shipped test files are info. |
| high | Test/spec files were packaged into the build (one finding per asar/root) |
| high | A |
| medium | Code points at a source map file |
| critical / high | A |
| medium | Client-side plan/license checks (heuristic, max 5 per file) |
| medium | A |
| info |
|
| high / medium | Debuggable or bypassable Electron binaries |
| info | An |
Every .asar is unpacked to a temporary directory (removed afterwards) and its
contents are scanned using paths like app.asar!/main.js. Files under
node_modules are scanned too, but their findings are reported one severity
lower: it is vendor code, not your logic.
Test paths (test/, tests/, __tests__/, e2e/, spec/, *.test.*,
*.spec.*) outside node_modules are treated as shipped test code. The scan
emits one tests.shipped finding per asar/root, and secret findings inside
those files stay visible but drop to info with a [test file, likely fixture]
prefix, so fixtures do not decide the grade.
Provider keys and PEM headers inside node_modules or any vendor/ path are
reported as info with a [vendor code] prefix. Vendor paths also skip
code.readable and downgrade sourcemap.comment, since that is third-party
code rather than yours.
Engine and binary surfaces
Surfaces are auto-detected; unrea_surfaces (MCP) lists them. Each one adds its own checks:
Surface | Check IDs |
|
|
|
|
|
|
|
|
|
|
When two surfaces see the same file, the more specific one owns it. Unity owns
*_Data/Managed, MonoBleedingEdge/ and its engine DLLs, so you don't get
generic noise about Unity's own files. Secrets are always reported.
Accepting a finding
Some findings are deliberate: a fuse your hooks depend on, a source map you
publish, a test fixture that really ships. Record that decision in
.unrea.json in the scanned target (or the current directory), or pass
--config <file>:
{
"accept": [
{
"id": "electron.fuses.run_as_node",
"reason": "hooks need ELECTRON_RUN_AS_NODE",
"path": "**/app.exe"
}
]
}Field | Meaning |
| Check id, or a family wildcard such as |
| Required. Why the finding is acceptable; a missing or empty reason fails the scan with a clear error |
| Optional glob over the finding location ( |
Accepted findings stay in
--jsonwithaccepted: trueandreason; text mode lists them underACCEPTED (n), one line each.They do not affect the grade and never trip
--fail-on.A critical secret (
secret.*) can never be accepted: unrea warns and keeps counting it. Rotate the key instead; a reason does not make it safe.MCP
unrea_scanapplies the same file and reports the accepted count.
CI / GitHub Action
name: unrea
on: [push, pull_request]
permissions:
contents: read
security-events: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci && npm run build
- id: unrea
uses: lordon1a/unrea@v1
with:
path: dist/win-unpacked
fail-on: high
- if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: unrea.sarif
- run: echo "unrea grade ${{ steps.unrea.outputs.grade }}"Inputs: path (required), fail-on (default high), version (default
latest), sarif (default unrea.sarif). The action sets up Node 22, runs
npx -y @yigitguldal/unrea@<version> scan, writes the SARIF report and the job
summary, and exposes outputs.grade.
Run the same pipeline outside Actions:
npx @yigitguldal/unrea scan ./dist --sarif unrea.sarif --summary report.md --badge unrea-badge.jsonSARIF levels: critical/high β error, medium β warning, info β note.
Accepted findings appear as suppressed results, so code scanning dismisses them
with the reason you gave.
Badge
--badge writes a shields.io endpoint document:
{ "schemaVersion": 1, "label": "unrea", "message": "grade A", "color": "brightgreen" }Commit it, or upload it to a gist, then embed the endpoint:
For a gist use
https://gist.githubusercontent.com/<user>/<gist-id>/raw/unrea-badge.json.
Colors: A brightgreen, B green, C yellow, D orange, F red. If CI
writes the badge, a later step can commit it or push it to the gist so the
badge follows the default branch; a gist keeps the repo clean.
Honest limits
Obfuscation slows, doesn't stop. Minifying or obfuscating raises the cost of reading a bundle; it does not protect a secret or a business rule.
The real fix is keeping secrets and valuable logic on your server. A client can only be trusted with what you are comfortable publishing.
asarextraction is trivial, source maps reconstruct readable code, and fuses only raise the bar for casual tampering.This is a heuristic scanner, not a pentester. Entropy rules produce false positives and can miss short or low-entropy secrets.
MCP gives an agent the same read-only scan results. Applying a fix plan is still a code change that you (or your agent) must review and test.
Development
npm install
npm test
node bin/unrea.js scan test/fixtures-or-tmp
node bin/unrea.js mcpTests use node:test, build fixtures in the OS temp directory, create a real
.asar with @electron/asar, and drive the MCP server with the official SDK
over stdio. Setup tests always set UNREA_HOME to a temp directory. No network
access is required.
FAQ
Can unrea make my app impossible to crack? No, and nothing can. Code running on the user's machine can always be read. unrea helps you make sure that what an attacker gets is worthless: no keys, no server-side rules, no free unlocks.
Is this an attacking tool? No. It only reads builds you point it at, and it's meant for your own apps. It doesn't patch, crack or bypass anything.
Do I need REA installed?
No. unrea runs on its own. A future unrea attack mode will be able to drive REA against your own build if you have it installed.
Does it send my code anywhere? No. There are no network calls, and scanning happens locally.
License
MIT Β© lordon1a
This server cannot be deployed
Maintenance
Related MCP Connectors
Security scanner for AI-written code: SAST, secrets, dependencies, IaC, containers and DAST.
Code intelligence platform for AI agents. 20 tools for architecture, security & impact analysis.
Threat modeling, code/cloud/pipeline scanning, shadow-AI discovery, compliance checks and fixes.
Zero-config MCP security scanner for AI-generated apps. 25K+ vulnerability patterns.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI-powered code safety analysis including risk detection, secret scanning, dependency checking, and code snapshot management. Works offline for basic features with optional cloud integration for advanced ML analysis and team collaboration.5 npm1Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI agents to inspect and reverse engineer local software targets, including binaries, JavaScript/Electron apps, .NET assemblies, and websites, returning evidence-backed findings for understanding and building similar features.478,884 npmMIT
- AlicenseNot gradedqualityCmaintenanceConnects AI agents to local analysis tools that inspect native binaries, JavaScript/Electron apps, .NET assemblies, and websites without source code, so features can be explained, traced, and rebuilt. Every finding is returned with its supporting evidence and stated limitations.478,884 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents (and a matching CLI) to inspect native binaries, JavaScript/Electron apps, .NET assemblies, Go/Rust/WASM artifacts, EVM bytecode, SQLite databases, recorded crashes, and websites without source code, explaining how features work and returning the evidence and limitations behind each conclusion. Analysis runs locally, using optional Hopper, Ghidra, or IDA providers for native targets.478,884 npmMIT