AI Security Review
scanned 12d ago · by lpm-firewall-aiNo confirmed malicious attack surface. The package is an explicit Relay companion CLI/MCP/daemon that can persist itself and integrate with local AI agents only after user-invoked setup/install.
Static reason
No blocking static signals were detected.; previous stored version diff introduced dangerous source
Trigger
User runs `relay pair`, `relay setup`, `relay install`, `relay daemon`, `relay mcp`, or `relay open`.
Impact
Package-aligned local Relay integration; no unconsented install-time execution or unrelated data theft identified.
Mechanism
User-invoked Relay CLI, MCP server, daemon, and agent-session materialization
Rationale
Static inspection shows powerful AI-agent integration and persistence features, but they are explicit product functionality activated by user commands and not lifecycle/import-time abuse. No concrete credential harvesting, unrelated exfiltration, destructive action, or unconsented AI-agent control mutation was found.
Evidence
package.jsonbin/relay.jssrc/install.jssrc/config.jssrc/client.jssrc/mcp.jssrc/task-daemon.jssrc/runtime.jssrc/setup-activation.jssrc/codex-session-writer.jssrc/claude-session-writer.jssrc/host-paths.js~/.relay/config.json~/.relay/task-ledger.json~/Library/LaunchAgents/work.relay.companion.plist~/Library/LaunchAgents/work.relay.companion.pill.plist~/.relay-companion~/.codex~/.claude
Network endpoints2
aia6vj5pgp.us-east-1.awsapprunner.comsendrelays.com
Decision evidence
public snapshotAI called this Clean at 86.0% confidence as Benign with medium false-positive risk.
Evidence for block
- src/install.js registers Relay MCP into Claude/Codex and creates macOS LaunchAgents, but only from explicit `relay setup`/`relay install` commands.
- src/runtime.js can launch Codex/Claude task agents with permissive settings for Relay background tasks, a high-risk but package-aligned capability.
Evidence against
- package.json has no preinstall/install/postinstall lifecycle hooks; main/bin only runs when invoked as `relay`.
- bin/relay.js dispatches explicit commands and does not run pairing, install, daemon, or agent launch at import time.
- src/config.js stores only Relay device config under ~/.relay and uses documented RELAY_* env overrides.
- src/client.js network traffic is to configured Relay API endpoints with bearer device token, matching package purpose.
- src/mcp.js exposes Relay messaging/task/connector tools over MCP; no credential harvesting or unrelated exfiltration found.
- No obfuscated payloads, destructive filesystem behavior, or reviewer/prompt manipulation found in inspected source.
Behavioral surface
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShell
HighEntropyStringsUrlStrings
NoLicense
Source & flagged code
3 flagged · loading sourcebin/relay.jsView file
•matchType = previous_version_dangerous_delta
matchedPackage = relay-companion@0.1.3
matchedIdentity = npm:cmVsYXktY29tcGFuaW9u:0.1.3
similarity = 0.762
summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta
This package version adds a dangerous source file absent from the previous stored version.
bin/relay.jsView on unpkg239const overlayMain = path.resolve(here, "../overlay/main.cjs");
L240: // require("electron") returns the path to the electron binary when resolved under node.
L241: let electronPath;
Medium
Dynamic Require
Package source references dynamic require/import behavior.
bin/relay.jsView on unpkg · L239src/install.jsView file
1import { spawnSync } from "node:child_process";
L2: import fs from "node:fs";
...
L50: const rootRes = spawnSync("npm", ["root", "-g"], { encoding: "utf8", timeout: 20_000 });
L51: const root = (rootRes.stdout || "").trim();
L52: const globalBin = path.join(root, ...PACKAGE_NAME.split("/"), "bin", "relay.js");
...
L67: try {
L68: const require = createRequire(path.join(packageRoot, "package.json"));
L69: const electronPath = require("electron");
...
L97: export function installDaemonAutostart(bin = relayBinPath(), node = process.execPath) {
L98: if (process.platform !== "darwin") return { ok: false, reason: "autostart_unsupported_platform" };
L99: const home = os.homedir();
L100: const plistPath = path.join(home, "Library", "LaunchAgents", `${DAEMON_LAUNCH_LABEL}.plist`);
Medium
Install Persistence
Source writes installer persistence such as shell profile or service configuration.
src/install.jsView on unpkg · L1Findings
1 Critical4 Medium5 Low
CriticalPrevious Version Dangerous Deltabin/relay.js
MediumDynamic Requirebin/relay.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencesrc/install.js
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License