AI Security Review
scanned 2d ago · by lpm-firewall-aiNo confirmed malicious attack surface. The package is a gateway-management CLI that stores local configuration and can wire Claude settings only when user-invoked.
Static reason
One or more suspicious static signals were detected.
Trigger
User runs agw commands such as init, target, login, doctor, completion, or key.
Impact
User-authorized project wiring, credential/session storage, gateway API administration, and status checks.
Mechanism
CLI-managed gateway configuration and API requests
Rationale
Static inspection shows suspicious primitives are aligned with a documented Agent Gateway CLI: explicit commands manage gateway targets, sessions, project credentials, and Claude local settings. There are no lifecycle hooks or hidden install/import-time behaviors indicating malicious intent.
Evidence
package.jsonREADME.mddist/main.js~/.agw/config.json~/.agw/auth-token~/.agw/sessions/*~/.agw/caps/*.json.agw.json.claude/settings.local.json
Network endpoints3
gateway.bitagent.devcompat.bitagent.devregistry.npmjs.org/-/package/bitspark-agw/dist-tags
Decision evidence
public snapshotAI called this Clean at 94.0% confidence as Benign with low false-positive risk.
Evidence for block
Evidence against
- package.json has no npm lifecycle hooks; bin agw points to dist/main.js only.
- dist/main.js main() only runs CLI logic after invocation, not on install/import.
- Network calls use configured gateway adminUrl plus package-aligned https://registry.npmjs.org dist-tags check.
- Writes are explicit CLI config/wiring actions: ~/.agw, .agw.json, .claude/settings.local.json, capability/session caches.
- child_process usage is package-aligned: git root discovery and opening browser for login.
- No evidence of credential harvesting, hidden exfiltration, persistence hooks, destructive behavior, or staged payloads.
Behavioral surface
ChildProcessCryptoEnvironmentVarsFilesystemNetworkShell
HighEntropyStringsUrlStrings
NoLicense
Source & flagged code
2 flagged · loading sourcedist/main.jsView file
22067patternName = generic_password
severity = medium
line = 22067
matchedText = if (!fro...t) {
Medium
70const here = dirname(fileURLToPath(import.meta.url));
L71: return JSON.parse(readFileSync(join(here, "..", "..", "package.json"), "utf-8")).version ?? "0.0.0";
L72: } catch {
...
L386: function defaultTarget(host, port) {
L387: return { adminUrl: `http://${host}:${port}`, compatUrl: `http://${host}:${port - 1}` };
L388: }
...
L457: ensureLegacyMigration();
L458: const hostOverride = strFlag(args.flags["host"]) ?? process.env["AGW_HOST"];
L459: const portOverride = strFlag(args.flags["port"]) ?? process.env["AGW_PORT"];
...
L470: flagTarget: strFlag(args.flags["target"]),
L471: cwd: process.cwd(),
L472: defaultHost: host,
Medium
Install Persistence
Source writes installer persistence such as shell profile or service configuration.
dist/main.jsView on unpkg · L70Findings
4 Medium5 Low
MediumSecret Patterndist/main.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/main.js
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License