AI Security Review
scanned 10d ago · by lpm-firewall-aiNo confirmed malicious attack surface is established. The suspicious primitives are package-aligned server/CLI behavior: serving HTTP, fetching user-specified URLs, loading user server entries, and forking a watch child process.
Static reason
One or more suspicious static signals were detected.
Trigger
User invokes srvx CLI or imports server adapters.
Impact
Runs a local/server HTTP handler and optional CLI fetches; no evidence of credential theft, persistence, or unconsented lifecycle mutation.
Mechanism
user-directed universal server CLI and runtime adapters
Rationale
Static inspection shows a zero-runtime-dependency universal server package with no install-time execution and no hardcoded exfiltration or persistence. The scanner hits are expected for a server CLI that loads user entry modules, serves files, forks its own watch process, and optionally fetches user-supplied URLs.
Evidence
package.jsonbin/srvx.mjsdist/cli.mjsdist/loader.mjsdist/static.mjsdist/adapters/node.mjsdist/adapters/service-worker.mjs
Network endpoints2
srvx.h3.devgithub.com/h3js/srvx/issues
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 install/postinstall lifecycle hooks; prepack is publish-time only.
- bin/srvx.mjs only imports dist/cli.mjs and calls main with docs/issues metadata.
- dist/cli.mjs child_process.fork is user-invoked serve/watch relaunch of its own CLI binary.
- dist/loader.mjs dynamic import loads the user's server entry path for the framework's documented server behavior.
- dist/cli.mjs fetch mode only calls user-specified URLs or local loaded handlers; no hardcoded exfiltration endpoint.
- No writes to AI-agent control surfaces, shell startup, VCS hooks, or persistence files found.
Behavioral surface
ChildProcessDynamicRequireEnvironmentVarsFilesystemNetworkShell
HighEntropyStringsUrlStrings
WildcardDependency
Source & flagged code
4 flagged · loading sourcedist/cli.mjsView file
4import { fileURLToPath } from "node:url";
L5: import { fork } from "node:child_process";
L6: import { createReadStream, existsSync, statSync } from "node:fs";
High
372async function forkCLI(args, runtimeArgs) {
L373: const child = fork(fileURLToPath(globalThis.__SRVX_BIN__ || new URL("../bin/srvx.mjs", import.meta.url)), [...args], { execArgv: [...process.execArgv, ...runtimeArgs].filter(Boolea...
L374: child.on("error", (error) => {
High
4Cross-file remote execution chain: dist/cli.mjs spawns dist/loader.mjs; helper contains network access plus dynamic code execution.
L4: import { fileURLToPath } from "node:url";
L5: import { fork } from "node:child_process";
L6: import { createReadStream, existsSync, statSync } from "node:fs";
...
L11: try {
L12: if (!process.env.NODE_ENV) process.env.NODE_ENV = cliOpts.prod ? "production" : "development";
L13: let server;
...
L90: }
L91: async function cliFetch(cliOpts) {
L92: const stdin = cliOpts.stdin || process.stdin;
L93: const stdout = cliOpts.stdout || process.stdout;
L94: const stderr = cliOpts.stderr || process.stderr;
...
L103: if (cliOpts.verbose && loaded.url) {
High
Cross File Remote Execution Context
Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.
dist/cli.mjsView on unpkg · L4dist/loader.mjsView file
41if (opts.interceptHttpListen !== false) {
L42: const loaded = await interceptListen(() => import(url), opts);
L43: mod = loaded.res;
Medium
Dynamic Require
Package source references dynamic require/import behavior.
dist/loader.mjsView on unpkg · L41Findings
3 High4 Medium4 Low
HighChild Processdist/cli.mjs
HighShelldist/cli.mjs
HighCross File Remote Execution Contextdist/cli.mjs
MediumDynamic Requiredist/loader.mjs
MediumNetwork
MediumEnvironment Vars
MediumWildcard Dependency
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings