@brna/cli
brna CLI — agent-friendly snapshot and action surface for React Native apps
Supply chain provenance
Status for the latest visible version.
Maintainers
Accepted risks
Findings the reviewer chose to accept rather than block on.
| Source | Rule | Reason | Accepted by | When |
|---|---|---|---|---|
| source-diff | source-size-tripled | AI (source-diff): Size increase from adding bun-built bundle; expected for CLI packages. | ai | |
| semgrep | semgrep:silent-process-exec-var | AI (semgrep): Same daemon spawn as silent-process-exec; not malicious. | ai | |
| semgrep | semgrep:env-bulk-read | AI (semgrep): Config env-replacement helper in CLI; not exfiltration. | ai | |
| source-diff | net-exec-file:dist/brna.js | AI (source-diff): Bun-bundled CLI entry point; network+exec from bundled dependencies is expected. | ai | |
| semgrep | semgrep:silent-process-exec | AI (semgrep): Daemon self-respawn pattern using process.execPath; standard CLI daemon lifecycle. | ai | |
| semgrep | semgrep:shady-links-raw-ip | AI (semgrep): All instances reference 127.0.0.1 in integration test setup — localhost loopback, not exfiltration. | ai | |
| typosquat | typosquat.levenshtein:joi | AI (typosquat): No brand similarity between @brna/cli and joi; weak Levenshtein match only. | ai | |
| semgrep | semgrep:env-spread | AI (semgrep): Fires exclusively in test files spreading process.env for test harness setup — not a runtime secret leak. | ai |
Versions (showing 5 of 5)
| Version | Deps | Published |
|---|---|---|
| 0.1.14 | 3 / 0 | |
| 0.1.13 | 3 / 0 | |
| 0.1.12 | 3 / 0 | |
| 0.1.0 | 3 / 0 | |
| 0.0.2 | 3 / 0 |
v0.1.14
1 findingPublished via CI/CD with Sigstore attestation (predicate: https://slsa.dev/provenance/v1). This is the strongest supply chain integrity signal.
v0.1.13
1 findingPublished via CI/CD with Sigstore attestation (predicate: https://slsa.dev/provenance/v1). This is the strongest supply chain integrity signal.
v0.1.12
1 findingPublished via CI/CD with Sigstore attestation (predicate: https://slsa.dev/provenance/v1). This is the strongest supply chain integrity signal.
v0.1.0
5 findingsThis version was published by a different npm account than previous versions on 2026-05-04. This could indicate a legitimate maintainer transition or an account compromise.
Newly added file contains both network calls and dynamic code execution. This is a hallmark of dropper/loader malware.
Silent detached process — runs invisibly in the background (reverse shells, miners) Source: https://github.com/leolin310148/brna/blob/60707f601f423feb1278423fec981b1e9c702ba1/src/daemon.ts#L270 268 | if (await pingDaemon(identity.socketPath)) return; 269 | await rm(identity.socketPath, { force: true }); > 270 | const child = spawn(process.execPath, process.argv.slice(1), { 271 | cwd: process.cwd(), 272 | detached: true,
Silent detached process — runs invisibly in the background (reverse shells, miners) Source: https://github.com/leolin310148/brna/blob/60707f601f423feb1278423fec981b1e9c702ba1/src/daemon.ts#L270 268 | if (await pingDaemon(identity.socketPath)) return; 269 | await rm(identity.socketPath, { force: true }); > 270 | const child = spawn(process.execPath, process.argv.slice(1), { 271 | cwd: process.cwd(), 272 | detached: true,
Published via CI/CD with Sigstore attestation (predicate: https://slsa.dev/provenance/v1). This is the strongest supply chain integrity signal.
v0.0.2
12 findingsSpreading entire process.env into an object — may capture all secrets 113 | ["bun", "run", CLI_PATH, "act", ...args, "--metro", baseUrl, "--timeout", "5000"], 114 | { > 115 | env: { ...process.env, NO_COLOR: "1" }, 116 | stdout: "pipe", 117 | stderr: "pipe",
Spreading entire process.env into an object — may capture all secrets 128 | async function runRaw(args: string[]): Promise<ProcResult> { 129 | const proc = Bun.spawn(["bun", "run", CLI_PATH, ...args], { > 130 | env: { ...process.env, NO_COLOR: "1" }, 131 | stdout: "pipe", 132 | stderr: "pipe",
Spreading entire process.env into an object — may capture all secrets 7 | function run(args: string[]) { 8 | return spawnSync("bun", ["run", CLI_PATH, ...args], { > 9 | env: { ...process.env, NO_COLOR: "1" }, 10 | encoding: "utf8", 11 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 41 | const result = spawnSync("bun", ["run", CLI_PATH, "config", "init"], { 42 | cwd, > 43 | env: { ...process.env, NO_COLOR: "1" }, 44 | encoding: "utf8", 45 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 91 | const start = spawnSync("bun", ["run", CLI_PATH, "trace", "start"], { 92 | cwd, > 93 | env: { ...process.env, NO_COLOR: "1" }, 94 | encoding: "utf8", 95 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 98 | const stop = spawnSync("bun", ["run", CLI_PATH, "trace", "stop"], { 99 | cwd, > 100 | env: { ...process.env, NO_COLOR: "1" }, 101 | encoding: "utf8", 102 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 227 | const proc = Bun.spawn(["bun", "run", CLI_PATH, ...args], { 228 | cwd, > 229 | env: { ...process.env, NO_COLOR: "1" }, 230 | stdout: "pipe", 231 | stderr: "pipe",
Spreading entire process.env into an object — may capture all secrets 71 | test("--format xml exits 4 with the expected stderr", () => { 72 | const result = spawnSync("bun", ["run", CLI_PATH, "snapshot", "--format", "xml"], { > 73 | env: { ...process.env, NO_COLOR: "1" }, 74 | encoding: "utf8", 75 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 82 | test('--format "" exits 4', () => { 83 | const result = spawnSync("bun", ["run", CLI_PATH, "snapshot", "--format", ""], { > 84 | env: { ...process.env, NO_COLOR: "1" }, 85 | encoding: "utf8", 86 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 92 | test("--format markdown alias is rejected", () => { 93 | const result = spawnSync("bun", ["run", CLI_PATH, "snapshot", "--format", "markdown"], { > 94 | env: { ...process.env, NO_COLOR: "1" }, 95 | encoding: "utf8", 96 | timeout: 5000,
Spreading entire process.env into an object — may capture all secrets 101 | test("--format JSON (case-different) is rejected", () => { 102 | const result = spawnSync("bun", ["run", CLI_PATH, "snapshot", "--format", "JSON"], { > 103 | env: { ...process.env, NO_COLOR: "1" }, 104 | encoding: "utf8", 105 | timeout: 5000,
Package was published without Sigstore provenance. Only ~12% of npm packages have provenance, so this is common but not ideal.