registry  /  srvx-nightly  /  0.11.21

srvx-nightly@0.11.21

Universal Server.

AI Security Review

scanned 10d ago · by lpm-firewall-ai

No confirmed malicious attack surface. The package is a universal server framework/CLI with user-invoked serving, static file serving, entry loading, and curl-like fetch behavior.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs srvx CLI or imports exported server adapters/modules.
Impact
Runs user server entries, serves local static files, or fetches user-specified URLs when explicitly invoked.
Mechanism
package-aligned server runtime and CLI utilities
Rationale
Static inspection shows suspicious primitives are aligned with a server framework CLI: dynamic imports load user server entries, child_process.fork restarts the CLI for watch/env-file handling, and network fetch is an explicit curl-like command. There is no lifecycle execution, credential harvesting, persistence, AI-agent control-surface mutation, or hardcoded exfiltration behavior.
Evidence
package.jsonbin/srvx.mjsdist/cli.mjsdist/loader.mjsdist/static.mjsdist/adapters/node.mjsuser-specified --entry/default server entryuser-specified --static/public directoryuser-specified -d @file request body.env.env.production.env.local
Network endpoints3
srvx.h3.devgithub.com/h3js/srvx/issuesgithub.com/unjs/jiti

Decision evidence

public snapshot
AI called this Clean at 95.0% confidence as Benign with low false-positive risk.
Evidence for block
    Evidence against
    • package.json has no install/postinstall lifecycle scripts; bin only maps srvx to bin/srvx.mjs.
    • bin/srvx.mjs only imports dist/cli.mjs and invokes main with docs/issues metadata.
    • dist/cli.mjs child_process.fork is CLI serve-mode self-restart/watch of its own bin, not install/import-time execution.
    • dist/cli.mjs fetch mode performs user-requested local handler or explicit remote URL requests; no hardcoded exfiltration endpoint.
    • dist/loader.mjs dynamically imports user-selected/default server entry files for framework loading, package-aligned behavior.
    • rg found no writes to AI-agent control surfaces, home persistence files, credential harvesting, or destructive filesystem calls.
    Behavioral surface
    Source
    ChildProcessDynamicRequireEnvironmentVarsFilesystemNetworkShell
    Supply chain
    HighEntropyStringsUrlStrings
    Manifest
    WildcardDependency
    scanned 19 file(s), 86.2 KB of source, external domains: github.com, srvx.h3.dev

    Source & flagged code

    4 flagged · loading source
    dist/cli.mjsView file
    4import { fileURLToPath } from "node:url"; L5: import { fork } from "node:child_process"; L6: import { createReadStream, existsSync, statSync } from "node:fs";
    High
    Child Process

    Package source references child process execution.

    dist/cli.mjsView on unpkg · L4
    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
    Shell

    Package source references shell execution.

    dist/cli.mjsView on unpkg · L372
    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 · L4
    dist/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 · L41

    Findings

    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