Vulnerability Research

Before the Model Gets a Debugger, We Audited jshookmcp's Source, Release Chain, and Backdoor Risk

At pinned source commit bb79e43d and npm 0.3.4 , SOSEC found no covert first-party backdoor; the default search profile reaches process execution, memory injection, browser-session data, remote extensions, and shared network state, and the release lacks source provenance, requiring high-privilege isolation for the service, browser, credentials, and target processes.

A warm hand-drawn forensic workbench places a sealed software package under a magnifying glass between a restrained AI terminal, source and dependency evidence, guarded network and process boundaries, and a cabinet of powerful security instruments.
In this article

Research basisStatic review of pinned source commit bb79e43d, npm 0.3.4 release artifacts, repository history, public advisories, issues, pull requests, and community reports; the package, dependencies, injection paths, and third-party extensions were not executed.

SourcePinned Git history / npm 0.3.4 registry tarball / GitHub advisory and issue records / public community reports / SOSEC static source and release audit

1 Audit conclusion and deployment boundary

At source snapshot bb79e43d60ffcd9fa3e330825f6e9efb0006d790 and in the registry tarball for @jshookmcp/[email protected], this audit found no first-party telemetry beacon, password-database scraper, self-updater, opaque command server, operating-system autorun installer, or concealed payload downloader. The conclusion is limited to readable first-party source, selected history, static npm artifacts, and public metadata. Package execution and dependency behavior remain outside the tested scope.

Following the default search profile through the server reveals its effective permission path. It reduces the schemas initially presented to the model. At the same time, search_tools defaults automatic activation to true. The meta-tools can discover an inactive tool, activate its domain, and pass it to call_tool, which loads and invokes the target. The activation handler checks whether a domain is known and leaves the selected profile outside the immutable authorization policy. A deployment that interprets “search profile” as “search-only permissions” grants substantially more authority than the label suggests.

What sits behind that bridge is unusually powerful even by security-tooling standards. The project advertises more than 600 tools across 34 domains. Public source includes arbitrary process launch, cross-platform memory writes, DLL and shellcode injection, Frida and debugger bridges, raw network probes, authenticated browser state access, local and remote JavaScript extension loading, and webhook management described by the project itself as C2 functionality. These are legitimate reverse-engineering and assessment capabilities. They are also the same primitives an implant would want after gaining execution. Intent is visible in naming, documentation, tool schemas, and ordinary control flow; consequence is determined by the operating-system account, browser profile, network position, enabled transport, and caller that receives the MCP connection.

This distinction explains why “is it a Trojan?” is the wrong single question. A concealed backdoor violates the operator's expected authority by hiding a second controller or data path. A dual-use server can be entirely candid and still be unsafe because the operator gave an untrusted model or remote client the authority it openly exposes. The audit therefore keeps two verdicts apart. The first-party code and published root package showed no covert controller in the inspected scope. The default deployment model does not provide a trustworthy least-privilege boundary for an untrusted, shared, or directly network-reachable client.

A text-free investigative workbench follows source history, package integrity, network access, and process authority toward one sealed package while a restrained AI terminal faces a cabinet of security instruments.
Figure 1. Implementation, release artifacts, and runtime authority are three separate evidence tracks. Readable source describes behavior; registry metadata identifies an artifact; deployment controls determine which callers and targets can exercise its authority.

1.1 Four audited objects define the evidence scope

The source object is the protected master branch at bb79e43d, authored on July 21, 2026. The installed object is npm 0.3.4, published on July 15 from lightweight tag v0.3.4 at cde13ed54517cca1a27a90d52a8824789294bcbb. Fourteen commits separate the tag and the pinned head, including a replacement for the embedding backend and several resource-control changes. The historical object includes 1,605 commits and earlier npm packages. The deployed object is whatever a user actually launches with its resolved dependency graph, environment variables, extensions, browser, operating-system privileges, and persisted state. A conclusion about one object cannot silently move to another.

The npm tarball was downloaded without running lifecycle scripts. Its registry SHA-1 was 90b95d7fe21d9fde8a1593c9c4a4479ba1d96cea, and its SHA-512 integrity was sha512-pKaXfOhYXxU0tYcj9+vyH2cRSgIrrYhloYjYIJrG9dzzak3pCuW/fCRKM2SxvfC8v74fP4tcLlqeUQyySBYm6w==. The archive contained 223 files and 3,413,305 unpacked bytes. No .node, .wasm, .exe, .dll, .so, browser binary, or nested archive appeared in the root package. Native code arrives through dependencies, not as an unexplained first-party binary hidden in this tarball.

The static sweep covered 1,341 production and release-related text files under source, scripts, packages, and workflows. It looked for process creation, dynamic evaluation, native injection APIs, credential paths, persistence mechanisms, download and update behavior, environment access, encoded blobs, telemetry SDKs, and literal network destinations. That method is intentionally biased toward finding dangerous capabilities, so raw match counts are not maliciousness scores. The source contains hundreds of terms such as shellcode, cookie, and base64 because it analyzes and manipulates those things. The meaningful question is where data enters, which guard runs, what sink receives it, and whether the behavior is disclosed.

Evidence objectIdentity fixed in this auditConfirmed scopeOutside this object
Source headbb79e43d60ff, 21 Jul 2026Current readable first-party implementation and history ancestryThat npm users received a bit-identical build or dependency set
Tagged releasev0.3.4 at cde13ed54517Release source chosen by the successful workflow runCryptographic source-to-package provenance; the tag is lightweight and unsigned
npm tarball0.3.4, registry integrity sha512-pKaX…Actual root-package files, manifest, bundle behavior, and registry bindingSafety of transitive native binaries, runtime downloads, or later extensions
Runtime deploymentOperator-specific account, transport, profile, state, browser, network, and extensionsReal authority and reachable consequencesAnything from source review alone without matching configuration evidence

1.2 Code and response: exposed authority, fixed versions, and required controls

Exact high-risk branch. The default profile is selected in src/index.ts, lines 106-115. The decision-relevant path begins in MCPServer.search.ts, lines 95-120, where search can activate results by default, continues through the domain and tool activation methods at lines 174-270, and reaches inactive-tool loading and execution in MCPServer.search.handlers.call.ts, lines 127-179. The state-changing branch is domain activation followed by invocation. The public branch shows that the profile reduces schema context without enforcing a hard allowlist.

Installed and source versions. The latest npm version at the July 24 cutoff was 0.3.4, tied operationally, but not cryptographically, to tag commit cde13ed54517. The pinned head bb79e43d60ff is fourteen commits newer while retaining package version 0.3.4; it must not be described as a published 0.3.5 or as code a normal npx @latest user receives. The public private-network probe flaw, CVE-2026-49856, is fixed in 0.3.2 and remains fixed in 0.3.4. Artifact history shows the same vulnerable mechanism in 0.2.9 and 0.3.0, although the global GHSA lists only 0.3.1.

Permanent repair is required for restricted deployments. A genuine restricted mode needs a server-side immutable allowlist applied to catalog search, automatic activation, explicit tool and domain activation, persisted-state restoration, and call_tool. It must deny tools outside policy even when a client knows the exact name. The legacy extension registry should be removed from production builds or redesigned so remote content cannot be imported into the main process. Modern plugin and workflow loaders need equivalent pre-import digest and signature enforcement, a real permission decision instead of hasPermission() returning true, and process isolation that can be destroyed after use.

What to do before that repair exists. Pin @jshookmcp/[email protected] with its registry integrity and reject @latest. Launch it only through stdio under a dedicated, non-administrative account in a disposable VM or container. Deny outbound network access except to named research targets, do not mount personal home directories or developer credentials, and never attach a personal browser profile. Remove access to the legacy extension-registry, maintenance installer, process launch, memory write, injection, cookie, storage, and raw-network tools at the client and operating-system layers; hiding their schemas is insufficient. Clear or protect ~/.jshookmcp/state so a prior activation cannot silently widen the next session.

Remote and shared use. If HTTP is unavoidable, bind to loopback, set a high-entropy bearer token, put TLS and independent authentication at a reverse proxy, firewall the port, leave MCP_ALLOW_INSECURE and proxy-trust overrides off, and run one server process per trust principal. Do not treat the MCP session ID as a tenant boundary. Activating the legacy extension registry can start a second listener on port 18789; that domain must remain absent unless its binding, body limits, HMAC policy, replay handling, and shutdown lifecycle have been repaired.

Acceptance evidence. A restricted build passes only when an out-of-policy exact tool name fails at search, activation, persisted restore, and direct call_tool; no second listener opens; no model or module is downloaded without an immutable revision and digest; destructive tools carry truthful annotations but remain blocked by deterministic policy; the process cannot read a personal browser or credential directory; and an independent operator can reproduce the package from a signed tag and match the registry artifact. Tool annotations and client confirmation are useful interfaces, not the enforcement root.

2 The search profile can activate the full catalog

jshookmcp has a real scaling problem to solve. Sending hundreds of tool schemas to a model consumes context, makes selection worse, and can exceed client limits. The search profile addresses that problem with a compact set of meta-tools. The model searches a generated catalog, describes a candidate, activates a domain or tool, and invokes the result. As a schema-delivery design this is sensible. The failure begins when the same mechanism is presented or interpreted as security minimization.

The source states the intention plainly: the meta-tools bridge the complete catalog. Search does not query a separately authorized subset; it can find tools that were inactive only because their schemas were withheld. The default auto_activate=true means discovery can change server state. activate_tool and activate_domain expose the transition directly. call_tool accepts a name and validated arguments, loads the inactive target, and executes it. None of those transitions proves that the original profile was entitled to the target.

A user instruction, untrusted page content, or an ambiguous request can lead a model across this line through ordinary tool selection. The official MCP trust model says local servers run with the access of ordinary installed software, clients should provide consent and sandboxing, and LLM-driven tool selection is expected behavior. Deterministic server authorization must therefore constrain the model independently.

2.1 Exact tool names bypass the profile check on the path to host action

The call chain matters because each individual step looks reasonable. Search validates its query. Activation checks that a manifest exists. The router validates arguments against the tool schema. Execution tracking applies timeouts and logging. These controls protect type and runtime integrity. They do not answer whether this principal may run this tool. A caller that can reach the meta-tools can move from a compact catalog to a full-tier domain without violating any of those local assumptions.

The distinction is easiest to see with process_launch_debug. The tool accepts an executable and argument array. The implementation reaches ProcessManager.impl.ts, lines 378-395, which invokes Node spawn, detaches the process, and unreferences it. Using an argument array without a shell reduces metacharacter injection. It does not make arbitrary binary launch read-only or harmless. If the search profile can activate and invoke that tool, the actual boundary is the Node process account and any client-side approval prompt.

Tool annotations do not repair the gap. The builder initializes the standard hints to false at tool-builder.ts, lines 93-104. Destructive process operations, including launch, kill, memory write, and injection, do not consistently mark destructiveHint. Even perfect annotations would remain untrusted metadata under the MCP specification. They can help a client explain risk, but a server must still reject an unauthorized call.

2.2 Yesterday's activation can return after a clean-looking restart

Activated domains are not necessarily confined to one conversation. The server creates a runtime snapshot scheduler and restores saved state. ServerRuntimeState.ts, lines 294-319 restores persisted domains, while the default storage root is ~/.jshookmcp/state. This is useful for resuming research, browser attachments, and expensive setup. It also means a later operator cannot infer current authority solely from the startup command or profile label.

Persistence here is not operating-system persistence in the malware sense. The audit found no startup-folder write, Run-key modification, LaunchAgent, scheduled task, or service installation. It is application state, openly implemented. Its security consequence is nevertheless real: a temporary decision to activate a high-risk domain can outlive the decision context. A restricted deployment must either disable state restoration, protect the state directory as policy input, or reauthorize every restored domain against an immutable allowlist before registration.

This is also why deleting one client configuration does not necessarily close the case. Responders need the process start time, effective transport and profile, restored domain set, state-directory contents, active extensions, browser target, listening sockets, and operating-system identity. A clean MCP client screen cannot prove that the server has returned to its original capability set.

Control surfaceWhat it currently doesWhy that is not authorizationRequired decision
MCP_TOOL_PROFILE=searchReduces initially listed schemasMeta-tools still bridge the complete catalogHard allowlist before search, activation, restore, and call
auto_activateLoads discovered tools by defaultDiscovery itself changes executable server stateDefault deny; require deterministic principal policy
Tool schema validationChecks argument shape and typesValid arguments can still request forbidden actionsAuthorize the tool, target, and effect after validation
Tool annotationsSupplies client-facing behavior hintsHints are incomplete and untrusted by specificationUse them for UX only, never as the policy root
Runtime snapshotRestores activated domains and other statePrior authority survives a later profile choiceReauthorize or discard restored capability state

3 Process injection, browser access, and payload tooling are active features

Security products can flag concrete high-risk behavior in this repository. The code contains the vocabulary and mechanics of process injection because process injection is a product feature. It attaches to browsers because browser instrumentation is a product feature. It extracts cookies and tokens from live traffic because authenticated replay is a product feature. It creates shellcode and traces system calls because exploit development and reverse engineering are product domains. A static scanner can conservatively flag those files while leaving the maintainer's intent unresolved.

This makes reputation evidence easy to mishandle. One April 23 LINUX DO post said a Huorong full-disk scan reported a Trojan in jshookmcp. The indexed post supplied no package version, file hash, detection name, scanner log, quarantine path, or vendor analysis. It cannot prove malware, and without those fields it cannot prove a false positive either. In our Windows audit environment, the local antimalware layer refused to read src/native/scripts/windows/inject-dll.ps1 with the operating-system error “file contains a virus or potentially unwanted software.” That observation identifies a file that triggers a control in one environment. It does not identify a malicious controller.

3.1 Memory injection remains active in TypeScript

The standalone PowerShell helper contains a safety-disabled message at lines 20-21. Reading only that file would produce the wrong system conclusion. The TypeScript implementation remains active. injector.ts, lines 53-152 reaches Windows WriteProcessMemory and CreateRemoteThread for DLL injection. Lines 288-376 allocate executable memory, write supplied shellcode, and launch it in the remote process. Linux and macOS paths use GDB or LLDB at lines 466-565.

The validation layer is not a human approval gate. Its default mode is balanced, set at injection-validator.ts, lines 446-460. In balanced mode, lines 320-367 do not require explicit confirmation. A caller can also request a disabled validation mode. The meaningful hard stops are process ownership, access tokens, integrity level, platform protections, container isolation, and whether the tool is reachable at all.

These named MCP tools expose code execution inside caller-selected processes. Operators should state that authority plainly during approval: "this server can start programs and inject code into processes available to its account." The shorter label "analysis tools" leaves out the consequence that matters to deployment.

3.2 A logged-in browser turns research convenience into credential authority

The browser domain can retrieve all cookies through CDP, including HttpOnly values available to the browser context. The schema is defined in definitions.tools.page-system.ts, lines 42-71, and page-data.ts, lines 194-217 returns the raw cookie values. The same handler reads local and session storage; another tool exports IndexedDB. The general redaction service protects selected logs and sandbox output, not these explicit data-return tools.

Auto-connect code searches ordinary Chrome profile locations and reads DevToolsActivePort. A browser launched by the project receives --no-sandbox and --disable-setuid-sandbox in BrowserModeManager.ts, lines 126-149. The source audit found no first-party parser that decrypts Chrome's Login Data password database. That negative fact does not reduce live session cookies to harmless metadata. An authenticated cookie, anti-CSRF token, or storage credential can be enough to act as the user without ever reading a saved password.

A dedicated empty browser profile forms the credential boundary. The profile should have no personal sync account, saved passwords, extensions, unrelated sessions, or access to the host's default profile directory. Research credentials should be scoped to the target, disposable, and revocable. Tasks that do not require cookie extraction should run with the relevant tools disabled.

3.3 Extension loading executes registry-supplied code in the server process

The project does use QuickJS isolation for one maintenance feature, and that boundary is genuine within its narrow scope. It does not enclose host process launch, browser CDP, native injection, legacy plugin imports, or modern extension workflows. The existence of a local sandbox therefore cannot be generalized into a claim that the MCP server or its privileged capability surface runs inside QuickJS.

The legacy extension-registry domain accepts HTTP(S), file://, absolute, and project-relative JavaScript module sources. PluginRegistry.ts, lines 281-309 downloads a remote module without an expected digest, signature, or size limit and caches it. Lines 180-213 dynamically import it into the main Node process. The execution tool can call a caller-selected export. This is explicit remote code loading, not a vulnerability that needs a gadget.

The domain is marked full-tier, but the search bridge can activate it. Loading its manifest starts a webhook server. The default port is 18789, and WebhookServer.impl.ts, lines 115-170 calls listen(port) without a host, normally binding all interfaces. Endpoint HMAC secrets are optional, request body collection is unbounded, and a stop method exists without a first-party lifecycle call that reliably pairs it with domain deactivation. The manifest openly calls this webhook/C2 management. Nothing is hidden; the default is still unsuitable for an untrusted network.

The newer extension manager adds an entry-file digest gate, but strict loading defaults on only when NODE_ENV=production. Workflow imports do not receive the same gate. Registry installation can clone a registry-selected repository and revision, install dependencies with lifecycle scripts disabled, then execute the package's own build script and import the result. Plugin-local .env values are merged into the main process, and hasPermission() returns true. Reloading removes registrations but cannot undo ESM side effects, timers, hooks, or global mutations.

First-party package integrity covers only the code present before an operator imports an extension. Once an extension executes in the main process, it inherits the server's filesystem, environment, network, browser, and native-tool position. Trust must be established on the exact extension bytes before import. Containment should end the extension process during cleanup because JavaScript unload cannot revoke completed side effects.

4 The backdoor sweep found no covert first-party control path

The audit records both its search targets and the scope of a negative result. The source pass searched first-party production and release files for startup and service installation, shell and process execution, dynamic code construction, credential stores, home-directory traversal, telemetry clients, hard-coded external endpoints, encoded payloads, native injection primitives, downloader behavior, and update channels. It then grouped matches by call path, keeping keyword hits separate from verdicts.

No operating-system persistence implementation appeared. The only matches for startup or service vocabulary belonged to code that analyzes other processes or Android startup logic. Application caches and runtime state live beneath ~/.jshookmcp. Lefthook installation can modify repository-local Git hook configuration, but only inside a checkout with .git; this is a development workflow side effect disclosed in postinstall, not an OS autorun path. The package does not register itself to start when the user logs in.

No covert first-party telemetry SDK or fixed analytics collector appeared. Names such as Sentry, Mixpanel, and Google Analytics occur in analyzer signatures used to recognize code in a target. Internal messages called “Telemetry Alert” are local execution warnings. Literal production URLs were dominated by loopback bridges, documentation, npm, Hugging Face model hosting, operator-supplied target patterns, and named tool vendors. There was no hard-coded first-party exfiltration domain or periodic beacon loop in the inspected source.

No opaque production binary was committed in the source tree. Binary-like tracked files were test fixtures: sample WASM, APK, ZIP, shared-object, executable, and raw-binary inputs used by parsers and exploit-development tests. The npm root tarball likewise contained no native executable. This reduces one common concealment channel. It does not audit the prebuilt binaries fetched or installed by dependencies such as Better SQLite, Isolated VM, Koffi, Sharp, ONNX Runtime, or esbuild.

4.1 The install script is readable, active, and broader than an ordinary JavaScript install

The root package declares scripts/postinstall.cjs. At the release tag, lines 10-79 attempt to load Better SQLite, Isolated VM, and Koffi, then may invoke node-gyp or npm rebuild --foreground-scripts. Failures are nonfatal. The code is not obfuscated and does not read root-package credentials or download a browser. Its purpose is to make optional native capabilities available across package-manager and Node-version combinations.

That transparency does not make lifecycle execution low-risk. Dependency installers may select prebuilt native objects or compile code. Better SQLite uses prebuild-install or node-gyp; Isolated VM uses node-gyp-build or a local build; Koffi has its own installer; esbuild runs its installer; the published Transformers chain can involve ONNX Runtime and Sharp. These scripts execute before the operator has inspected the final dependency graph. Installing with an unrestricted developer account gives all of them that account's privileges.

The package's own archive allowlist is tight: dist, workflows, native helper scripts, and the postinstall file, plus npm-mandated metadata and readmes. Only dist/index.mjs is executable in the tar metadata. Normalized archive timestamps improve deterministic packing. They do not create reproducibility because the workflow does not perform an independent second build and compare hashes, while Node 22, ubuntu-latest, action tags, and dependency ranges can move.

4.2 Explicit network features include two mutable download paths

Many tools naturally contact caller-selected targets: browser navigation, GraphQL replay, source-map retrieval, raw network requests, CAPTCHA services, webhooks, ADB debug endpoints, Ghidra and IDA bridges, and extension registries. A static allowlist of all destinations would defeat the product. The appropriate control is purpose-specific egress: a research job receives only the target ranges, package mirrors, and local bridges it actually needs, while metadata services, internal management networks, personal SaaS, and arbitrary Internet destinations remain denied.

The embedding model is different because the server chooses the supply source. Published 0.3.4 uses Transformers.js to load Xenova/bge-micro-v2 without a fixed revision or expected digest. The current head replaces that chain with a static backend, but StaticEmbeddingModel.ts, lines 166-208 constructs Hugging Face resolve/main URLs for tokenizer.json and model.safetensors, follows redirects, and caches the bodies without an expected SHA-256, signature, immutable revision, or byte ceiling. The 15-second abort is cleared after response headers, so it does not bound a stalled or oversized body.

Safetensors constrains the fetched artifact to model data. A changed artifact can still poison tool search, consume disk or memory, reach native tokenizer parsing, or exploit a future parser bug. This path is an unpinned model supply-chain input. A deployment should pre-provision reviewed model files, verify their digests before use, impose byte and streaming deadlines, and disable model network access when vector search is unnecessary.

4.3 Antivirus reports need fixed sample identifiers

The Huorong anecdote is useful because it shows what users are seeing, but it lacks the fields needed for attribution. A responsible report would preserve the package version, registry integrity, exact detected path, file SHA-256, product and engine version, signature family, quarantine action, and whether the file came from the root package, npm cache, a dependency, a generated build object, or a browser download. Without those fields, “jshookmcp was detected” collapses several different objects into one name.

Our local block on inject-dll.ps1 has a narrow evidentiary scope. The file name, surrounding repository, and active TypeScript injection implementation provide a plausible heuristic reason for scrutiny. The local scanner's refusal did not identify the signature, and the file was not executed. The quarantined worktree copy remained untouched; the pinned Git object and commit-hosted source view supplied the analysis evidence. This preserved safety and provenance.

A credible maliciousness finding would require evidence of concealed control: an unexplained destination, secret-dependent activation, deceptive install branch, encoded second stage, credential collection unrelated to declared tools, persistence outside the stated application state, or a published artifact that diverges materially from its source. None appeared in the inspected first-party objects. The absence of those indicators does not certify every dependency, extension, future commit, or npm publication.

Backdoor indicatorObserved resultInterpretationResidual gap
Hidden command or telemetry endpointNone identified in first-party production sourceNo evidence of a covert first-party controllerDependencies, extensions, runtime configuration, and future artifacts remain outside that negative
OS autorun or service persistenceNone identified; application state and repository Git hooks are explicitNo malware-style startup installation foundAn imported extension has main-process authority and could add one
Credential collectionNo password-database decryption; explicit live cookie, storage, token, and secret-analysis tools existDeclared capability, high consequenceA caller can return raw authenticated state when those tools are reachable
Opaque first-party binariesNone in npm root package; repository binaries are test fixturesFirst-party behavior remains substantially reviewableNative dependency prebuilts and runtime model files were not independently audited
Dynamic remote codeExplicit extension download, build, import, and export invocationDocumented delegated code executionRegistry and extension identity are not cryptographically enforced end to end

5 The release has an operational source link and a provenance gap

The positive release evidence is stronger than an arbitrary tarball upload. Tag v0.3.4 points to cde13ed54517. GitHub Actions run 29432085723 has that head SHA. Checkout, package verification, packed-install smoke tests, and publish completed successfully. npm recorded 0.3.4 during that workflow's publish window. The dependency fields, optional dependencies, file allowlist, binary entry point, and postinstall in the registry package correspond to the tag manifest. No unexplained root dependency or extra executable appeared.

The missing link is cryptographic provenance. The tag and commit are unsigned. Registry metadata has no gitHead and no npm provenance attestation. The workflow uses a long-lived NPM_TOKEN, lacks id-token: write, and does not enable provenance in publish-packages.yml, lines 9-62. The npm publisher name vmoranv6 and GitHub actor vmoranv are operationally associated but not cryptographically linked by the package record.

The registry's ECDSA signature protects the name, version, and integrity binding provided by npm. It does not say which repository and workflow produced the bytes, and it does not say the bytes are safe. npm provenance would add a Sigstore-backed statement connecting a supported CI identity, repository, and build invocation to the package. Trusted OIDC publishing would also remove the long-lived token from the release path. Neither control replaces source review, but both make the reviewed object identifiable.

5.1 Twenty-two npm versions map to fourteen tags and no GitHub Releases

The repository was created on February 21, 2026, and npm began publishing on March 7. By July 15 it had produced 22 package versions. Git contains fourteen version tags. Eight npm versions, including 0.1.2, 0.1.3, 0.1.4, 0.1.6, 0.1.9, 0.2.5, 0.2.8, and 0.2.9, have no matching tag. Only v0.1.5 and v0.3.1 are annotated; the rest are lightweight. GitHub exposes no Release objects.

These gaps raise the cost of answering ordinary incident questions: which commit produced version 0.2.9, what changed between two registry artifacts, where the release notes live, which checksum the maintainer endorsed, and which source support window applies. The public SECURITY.md compounds the problem by retaining GitHub's placeholder table for nonexistent 5.1.x, 5.0.x, and 4.0.x branches. It provides no usable reporting address, supported version range, acknowledgement window, or response target.

The release workflow accepts any v* tag and manual dispatch. No assertion ties github.ref_name to v plus the package.json version. Action dependencies use mutable tags such as actions/checkout@v7 and actions/setup-node@v6; full commit SHA pinning is absent. A pull_request_target gate runs a third-party anti-slop action with pull-request write authority. These controls create mutable supply-chain inputs; this audit found no public record showing they had been abused.

5.2 Reproducibility stops where the consumer's dependency graph begins

The tag lock contains 895 package records; the current head lock contains 842 after embedding changes. Every inspected lock record has an integrity value, and no Git, VCS, or direct-URL dependency resolution appeared. The release job packs and smoke-tests the same tarball it later publishes. Those are meaningful controls. Consumers do not receive the pnpm lockfile or its overrides, so normal npm installation resolves semver ranges independently of the CI graph. Two users installing 0.3.4 on different dates can receive different transitive versions.

A stronger release would build once in a tokenless job, produce the tarball, SBOM, dependency lock, checksums, and test evidence, then transfer only that hash-addressed artifact to an isolated OIDC publication job. The tag would be signed, action and container inputs pinned to full SHAs or digests, and the workflow would prove tag-version equality before touching the registry. A second clean build could compare the tarball hash or document unavoidable nondeterminism.

For current operators, the practical substitute is to retain the exact registry tarball and integrity, create an internal lock from an approved installation, verify registry signatures and available attestations, inventory native package binaries, and promote that frozen object through environments. Re-running npx -y @jshookmcp/jshook@latest during every client launch trades away that identity each time.

5.3 Two dependency advisories require reachability analysis

The 0.3.4 release manifest makes @huggingface/transformers:^4.2.0 optional, and the release lock resolves Sharp 0.34.5. GitHub advisory GHSA-f88m-g3jw-g9cj covers Sharp before 0.35.0 through inherited libvips behavior when processing untrusted GIF, TIFF, or VIPS images. The relevant semver range cannot float to 0.35.0. The audited jshook embedding path is text-oriented, and we did not demonstrate an untrusted image reaching the vulnerable decoder. This is exposed dependency code with conditional reachability, not a proven exploit path through jshookmcp.

Both release and current head locks contain [email protected]. The encoding tool accepts caller-supplied proto text or a path and invokes protobuf.parse() or protobuf.load() at handlers.impl.core.runtime.ts, lines 411-422. GHSA-j3f2-48v5-ccww describes an infinite loop on malformed option syntax fixed in 8.6.6, giving the denial-of-service path plausible tool-level reachability. A separate text-format prototype-mutation advisory affects the locked version, but no import of that extension was found.

Fresh semver resolution may now select a fixed protobuf release, while an approved lock or reproducible tag build preserves 8.6.4. The package version and installed dependency graph therefore require separate identities. The maintainer should publish a version that removes the old Transformers and Sharp chain, requires protobuf 8.6.6 or later, and supplies a release lock or SBOM. Operators should confirm actual installed versions from the deployed dependency graph.

Release propertyEvidenceAssessmentAction
Root tarball scope223 files; no root native binary or nested archiveTightly scoped and substantially reviewableRetain exact tarball and registry integrity
Workflow correspondenceSuccessful run 29432085723 at tag SHAStrong operational linkKeep pack-and-test behavior
Source provenanceNo gitHead, npm provenance, signed tag, Release, or SBOMIdentity gap remainsOIDC trusted publishing, signed tags, attestations, checksums
Build inputsMutable action tags, Node line, runner image, and dependency rangesRebuild can driftPin SHAs and digests; compare clean-build hashes
Install behaviorNative dependency lifecycle execution and fallback rebuildsExpected but high-trust install surfaceBuild in isolation; make optional native rebuilds explicit
Runtime modelMutable Hugging Face revision with no expected digestUnpinned supply-chain inputPre-provision immutable, hash-checked files with byte limits

6 One public SSRF flaw shows how a local policy can miss a neighboring tool

GHSA-c5r6-m4mr-8q5j and CVE-2026-49856 describe a medium-severity authorization bypass in the network domain. Raw HTTP, TCP, TLS RTT, and latency-stat tools used a central SSRF policy that denied private and reserved targets unless the request carried explicit authorization. ICMP probe and traceroute resolved the target and called native sinks without that policy. A client with the network domain could therefore learn internal reachability, approximate latency, hops, and ICMP error classes from the server's network position.

The demonstrated impact is reconnaissance through ICMP and traceroute. Cloud metadata response bodies, internal HTTP responses, service writes, and code execution are outside this path. The probes become most useful to an attacker when Streamable HTTP exposes the server remotely, multiple callers share one network position, or Windows provides ICMP without administrator rights. Linux and macOS generally need root or CAP_NET_RAW for raw ICMP. No public evidence shows exploitation.

The flaw demonstrates policy drift. The project already had the correct central helper, and neighboring handlers in the same file used it. Two newly added tools took a shorter resolver-to-sink path and changed the promised boundary. A catalog this large requires every route to a sensitive sink to pass through the same enforced policy.

6.1 Artifact history moves the affected range back from 0.3.1 to 0.2.9

The global GHSA declares only 0.3.1 affected and 0.3.2 fixed. Commit and tarball history show a wider mechanism range. Commit b5e3b00f91d1d4601c0c82a46960bb1f58ca8f23 introduced the ICMP and traceroute tools on April 20. npm 0.2.8 predates those tools. Packages 0.2.9, 0.3.0, and 0.3.1 contain the unguarded mechanism. Commit 02111311f7bd0f86a7d7ef8538986594b3a18afa is the first fix and is the v0.3.2 tag target.

The mechanism supports an affected publication range of >=0.2.9 <0.3.2. Reachability additionally required an activated network domain, caller tool access, and a working ICMP provider on the platform. The correction matters for inventory: a team running 0.3.0 should patch even though the global advisory names 0.3.1.

npm versionPublished UTCVerified mechanism stateRegistry SHA-1
0.2.818 Apr 2026 08:44No ICMP or traceroute toolsd36dce1190c57078e7401a3d8446ddffdbcd33e7
0.2.924 Apr 2026 09:46First vulnerable publication found02f91efc96cfa64c1b5cd35399b4894f9f529430
0.3.01 May 2026 15:37Vulnerable resolver-to-sink path6183d6abf10636c7c82b8c211e6e8f36ec9f5a0c
0.3.116 May 2026 11:25Vulnerable and advisory-listede95ff56cbb23e9c85e67ee8b11d53337670ac738
0.3.227 May 2026 05:48First fixed publication5e96623dbbe366a076494e22177b38ef98f811e8
0.3.415 Jul 2026 16:26Current latest; fixed guard retained90b95d7fe21d9fde8a1593c9c4a4479ba1d96cea

6.2 The vulnerable path resolved an address and went straight to the native sink

At advisory snapshot d309c395738638e384c28c0f599b47b2213ab595, a direct MCP call or the search-profile call_tool path reached the router and network manifest. handleNetworkTraceroute(), lines 114-143 and handleNetworkIcmpProbe(), lines 232-260 called resolveHostname(). That helper returned IPv4 literals unchanged or the first DNS A result, then the handler passed the address to traceroute() or icmpProbe().

The missing call is the finding. RTT and latency-stat handlers parsed an authorization object and called resolveAuthorizedTransportTarget(). ICMP and traceroute did not. Argument validation correctly recognized a target string; DNS resolution correctly produced an address; the native provider correctly sent probes. Every local function did its job while the end-to-end policy failed.

The published advisory describes a local full call_tool regression test with fake native sinks. The checked-in fix contains direct handler tests. These tests verify the missing and repaired handler policy. A catalog-wide invariant test is still needed to enumerate every network-capable tool and prove private-address denial through the same public dispatch path a model uses.

6.3 Loopback behavior and the two-stage authorization rollout

Fix commit 02111311 replaces the plain resolver on both paths. The handlers parse network authorization, call a shared host-target policy helper, and pass only an approved resolved address to the native sink. The regression test covers private targets and authorization cases. The relevant current-head handler is byte-identical to the v0.3.4 source, and the npm bundle contains the fixed authorization behavior. Operators on 0.3.2 or later have the private-network fix.

Loopback is a deliberate exception. The helper excludes isLoopback from private-address rejection, and the regression test expects 127.0.0.1 to reach both sinks. This conflicts with the advisory's literal statement that loopback is blocked by the central policy. The legacy global override ALLOW_LOCAL_SSRF=true also permits private targets when no request policy is supplied. These details leave the original private-range repair intact and belong in the deployment threat model.

Versions 0.3.2 and 0.3.3 applied the default deny but did not expose the request-scoped authorization field in the probe tool schema. Commit bd05892d816e1b137c432a9853dd7bcba7f2812b, first released in 0.3.4, made that authorization available to clients. The repair story is therefore two-stage: 0.3.2 closes unauthorized private probing, and 0.3.4 exposes the intended scoped exception path.

7 Repository history shows fast maintenance and concentrated control

The repository grew from its first commit on February 23 to 1,605 commits at the July 21 snapshot. Git authorship assigns 1,592 commits, or 99.19 percent, to vmoranv and thirteen to Dependabot. Only 26 commits are merges. The count reflects an unusually fine-grained, direct-to-master history and records only 26 visible merge reviews. Three external pull requests merged, but their authors do not appear in shortlog, consistent with changes being squashed or recreated.

One maintainer can preserve architecture and respond without coordination delay. The same account also carries the effective bus factor, release authority, package publishing, primary review, and policy interpretation. Account compromise, burnout, or a mistaken broad change therefore meets fewer independent brakes. The project had 1,813 GitHub stars and 444 forks at the July 24 cutoff, with four subscribers. Stars measure attention; release authority and security review remain concentrated.

7.1 Ordinary bug response is often fast, while the long tail and security channel remain weak

GitHub's issue endpoint contained thirteen non-PR issues, all externally reported and all closed. Median closure was about 8.8 hours. The maintainer explicitly commented on eleven, with a median first-comment time around 3.3 hours. Issue #44, concerning a missing packaged module, received a maintainer response in under three minutes and closed in under three hours. Issue #10 led to external PR #11 and a packed-artifact fix within roughly 4.5 hours.

The response-time distribution matters more than the median. Five issues remained open longer than seven days. Issue #77, about screenshots being written into an npx cache instead of the configured directory, waited roughly 24 days for its first maintainer comment and closure. The placeholder SECURITY.md leaves reporters without a private channel or a documented supported release.

The public advisory offers one positive security-response example. The repository advisory for CVE-2026-49856 was published around twenty minutes after the fix commit on May 27, and npm 0.3.2 followed within an hour. GitHub's global reviewed record arrived July 1. Repair preceded broad database notification. The inaccurate lower bound and loopback wording show why coordinated disclosure also needs artifact-range review and editorial precision.

7.2 Pull-request moderation is aggressive because the project was flooded with low-trust change

Of 74 pull requests in the reviewed period, 24 merged, 46 closed without merge, and four Dependabot items remained open. Dependabot authored 32; the maintainer authored 20; external humans authored 22. Only three external-human PRs merged, all from one contributor in March. Median closure for an external-human PR was about 4.4 hours. Several repeated screenshot-fix submissions closed in seconds, a timing pattern consistent with automation; issue metadata does not identify the closing actor.

An April cluster explains the project's current tone. PR #26 proposed 18,831 additions across 75 files and closed unmerged after about three minutes. Five split follow-ups also closed. In a maintainer-authored LINUX DO post, vmoranv described the submissions as out of scope, AI-generated, repeatedly force-pushed, and incompletely validated. The characterization is anecdotal; the change sizes and closure outcomes are public facts.

The pinned PR template now contains an AI honeypot token, and the quality gate auto-closes one hard-signal failure while treating softer signals as warnings. CONTRIBUTING.md still describes a broader zero-tolerance posture and therefore lags the hard/soft split added in bb79e43d. This governance style may protect a one-person maintainer from review exhaustion. It can also deter careful external security work unless the project offers a clear private channel and separates behavior evidence from authorship suspicion.

7.3 Reputation directories provide discovery signals only

Agent Reputation displays no native ratings; its visible 4.0/5 is one imported signal derived from GitHub popularity. Protodex labels the project "Clean" without exposing a scanning method on the listing. Third-party catalogs disagree on tool counts because their crawls represent different commits. These surfaces help discovery, while the approval decision still requires exact package bytes, dependency graph, privileges, and deployment controls.

A March community thread reported multiple high-CPU headless-browser processes. The maintainer publicly acknowledged investigation on March 20, said a new version fixed process cleanup on March 21, and tag v0.2.2 followed that day. The record connects a user-visible symptom, maintainer response, and release. Coverage of every orphan-process path remains unverified. Recent head commits adding server-instance detection, browser-session reclamation, cache budgets, and worker bounds show continued work on resource pressure.

Governance signalObserved factWhat it supportsWhat remains weak
Maintainer concentration99.19% of commits attributed to one authorFast coherent iterationBus factor, release authority, and review independence
Issue response13 external issues closed; median 8.8 hoursActive ordinary maintenanceLong-tail delays and no public SLA
Security responseFix and repository advisory on 27 MayAbility to coordinate a repairAdvisory range and loopback language need correction
Release records22 npm versions, 14 tags, no GitHub ReleasesFrequent deliveryIncomplete version-to-source and support record
Security policyUntouched placeholder for nonexistent 4.x and 5.x branchesNothing operationalNo private channel, support window, or response expectation

8 Deployment baseline: disposable, single-principal isolation

The practical threat model centers on a model, prompt-injected page, compromised client, or remote caller choosing among host-level security primitives. The baseline resembles a malware-analysis workstation: a disposable trust zone with explicit target access, no personal data, no standing cloud credentials, and no route to internal management networks.

The default stdio transport creates no listener and limits protocol access to the spawning client. Host isolation still depends on the operator. Run the process as a dedicated user that cannot debug other users' processes, read their homes, or access a valuable browser session. A container can scope filesystem and network access; process injection, raw sockets, ptrace, devices, host networking, and mounted browser directories must remain absent.

8.1 Build a disposable research lane

Start from an exact package tarball and internal lock. Build it in an isolated environment with no secrets and retain every native binary hash. Promote the resulting image and disable reinstallation from public ranges at launch. Preload the reviewed embedding model or disable vector search. Mount only the samples and output directory required for the case. Use separate read-only mounts for reference tools and a capped writable scratch volume for captures, caches, and generated code.

Give each engagement an egress policy. Browser and replay tools may reach the authorized target and its explicitly required identity or asset providers. Package installation, extension registries, arbitrary webhooks, metadata IPs, RFC 1918 networks, localhost services outside the lab, and personal SaaS remain blocked. Raw ICMP and traceroute are enabled only when network mapping is in scope. ALLOW_LOCAL_SSRF stays unset. DNS answers are logged with the tool call because a hostname can change its address after approval.

Use a purpose-built browser profile with disposable credentials. Do not attach to the operator's normal Chrome. Restore browser sandboxing unless a documented target incompatibility requires an isolated exception. Store cookies and captures as secrets, redact them from general model context, and destroy the profile at case closure. A model should receive only the session material required for the current operation, not the whole browser's state simply because CDP can return it.

At the client, require human confirmation for process launch, kill, memory write, injection, extension install, workflow load, cookie export, credential extraction, raw packet or ICMP operations, and webhook forwarding. Confirmation text should display the exact executable, PID, module URL and digest, destination, browser profile, or file path. Because annotations are incomplete, client policy must bind exact tool names and arguments; server hints alone are insufficient. Server-side and OS enforcement remain mandatory in case the client is compromised.

8.2 Streamable HTTP shares process-level authority across sessions

Loopback limits direct external reachability. Other users, compromised developer tools, and hostile local processes on the same host remain in scope. Where a local network transport is necessary, a Windows named pipe or Unix domain socket with operating-system access controls expresses a single-principal boundary more accurately than an unauthenticated loopback TCP listener. A parent-held stdio channel remains the safer default.

When selected, HTTP defaults to 127.0.0.1:3000. Non-loopback binding without a token is rejected unless MCP_ALLOW_INSECURE=1. Bearer comparison is constant-time. Request bodies have a default 10 MiB cap, and rate-limiting and proxy controls exist. Those are useful protections. The route supplies no TLS, accepts requests without an Origin, and treats a configured token as sufficient for Origin handling. A reverse proxy and firewall remain necessary for any remote use.

The multiplexed transport creates random UUID session IDs and rewrites JSON-RPC IDs, preventing ordinary response confusion. Notifications are broadcast to all active sessions. Domain instances, activation maps, extension registries, event state, memory sessions, and many caches live on the shared server. Browser coordination has some per-session selection; the process does not bind each session to a separate identity, token, filesystem, network policy, or capability set.

One server per trust principal is the minimum remote architecture. A bearer token grants access to one process, whose internal authority stays shared. Separate teams, customers, or automation identities need separate processes, state directories, browser profiles, extension roots, network namespaces, and tokens. Session IDs belong to response routing and should never be used as authorization evidence.

8.3 Monitoring must record state changes and targets

An audit log should bind client identity, server package and dependency digest, effective configuration, state snapshot ID, tool name, validated arguments after secret redaction, activation source, target PID or network destination, start and finish times, result class, files written, listeners opened, child processes, extension digest, and operator approval. Raw secrets belong in a restricted evidence store, not the general log. Logs must leave the server trust zone so an imported extension cannot rewrite the only copy.

Detection should focus on transitions that alter later authority: activation of a full-tier domain, restoration of a domain absent from startup policy, launch of port 18789, a new remote module or workflow, change to plugin roots or .env, use of disabled validation mode, browser attachment to a non-lab profile, execution against an unexpected PID, private or loopback network probes, MCP_ALLOW_INSECURE, ALLOW_LOCAL_SSRF, and outbound requests to model or registry hosts outside the approved release.

If compromise is suspected, stop new MCP calls and preserve the server process, state directory, npm cache, exact tarball, dependency tree, extension cache and repositories, browser profile, listening sockets, child-process tree, network logs, and client conversation that selected the tool. Revoke research credentials and browser sessions from a clean environment. Reinstallation leaves any imported module side effects, injected process, or detached child available for separate investigation.

Recovery creates a new image from reviewed artifacts. Change tokens and credentials, verify that no unexpected process or listener remains, discard persisted activation state, and restore only necessary case data. Run a canary case with constrained egress and no secrets. Independent review must confirm that exact-name calls to forbidden tools fail before general service resumes.

Deployment decisionMinimum safe positionEvidence to retainStop condition
Package identityPin 0.3.4 tarball and internal dependency lockRegistry integrity, native hashes, image digest, SBOMAny unexplained byte or dependency drift
Execution accountDedicated non-admin user in disposable isolationUID/token, mounts, capabilities, seccomp or sandbox policyHost ptrace, raw devices, personal home, or broad credential access
TransportStdio; otherwise loopback HTTP plus token, TLS proxy, firewallListener, proxy config, token rotation, process ownershipWildcard or unauthenticated listener; shared trust principals
BrowserDedicated empty profile with scoped disposable accountProfile path, browser flags, active sessions, destruction receiptAttachment to personal or production-admin profile
ExtensionsDisabled, or immutable digest allowlist in separate processSource commit, built bytes, signature, digest, permission policyRemote mutable source, arbitrary target directory, or main-process import
NetworkCase-specific targets only; no internal or metadata routesDNS result, destination, policy decision, packet or proxy logUnexpected private, loopback, registry, model, or webhook destination

9 Controls that would strengthen project trust

jshookmcp's value comes from collapsing a complicated reverse-engineering workstation into a discoverable interface. That value does not require minimizing what the interface can do. The strongest next step is a capability architecture that makes powerful intent explicit: small separately packaged domains, immutable server-side policy, process isolation, target-scoped network brokers, dedicated browser contexts, extension attestation, truthful destructive annotations, and audit records that follow every state change.

Release trust can improve independently. The maintainer can replace the placeholder security policy with supported versions and a private reporting channel, correct the GHSA range and loopback wording, publish GitHub Releases with signed tags and checksums, move npm to OIDC trusted publishing with provenance, pin workflow actions, provide an SBOM and release lock, hash remote model files, and publish the current dependency fixes as a new version with distinct labels for head and npm.

Governance needs another human at the release boundary. A second maintainer or named security reviewer does not need to slow everyday commits. They can own protected release approval, advisory range review, extension trust changes, and high-risk sink policy. External contributors need a documented route for security evidence that does not pass through public anti-slop automation. The project's fast response is worth preserving; independent review should be concentrated where a single mistake changes the authority of hundreds of tools.

9.1 What would change this verdict

The no-covert-backdoor conclusion would change with evidence of a hidden first-party destination, deceptive lifecycle branch, secret-triggered behavior, unexplained artifact divergence, unauthorized credential collection, or concealed persistence. The deployment-risk verdict would improve when restricted profiles become enforced allowlists across search, activation, restore, and call; extensions execute outside the main process from immutable verified bytes; HTTP becomes single-principal by construction; dangerous tools require deterministic authorization; and browser and native capabilities run inside disposable operating-system boundaries.

The supply-chain verdict would improve when a signed source tag, immutable workflow, provenance attestation, release artifact, checksums, SBOM, dependency lock, and reviewed runtime model digest form one chain. Star counts, directory badges, CI results, and registry signatures remain useful signals with narrower roles.

The vulnerability record would improve when the maintainer updates the affected range to include 0.2.9 and 0.3.0, explains that loopback remains allowed, documents the difference between the 0.3.2 default deny and 0.3.4 request-scoped authorization schema, and adds a catalog-wide public-dispatch invariant test. Those details determine which users patch and what operators believe the policy guarantees.

9.2 Final assessment

This assessment is fixed to source commit bb79e43d and the npm 0.3.4 artifact. A new package or source commit, changed dependency resolution, a different model or extension source, multi-tenant HTTP deployment, attachment to a production browser, or changes to allowlist and persisted-state logic should trigger a new review.

Source, release artifacts, vulnerability history, and runtime boundaries support classifying jshookmcp as high-privilege dual-use infrastructure. The audited scope contained no intentional first-party backdoor. Default operation can still move a model-selected call into process execution, memory injection, session-data access, remote extension loading, and shared network state.

The project is suitable for a disposable, low-privilege, target-scoped research environment. A personal workstation, shared daemon, production network, automatically approving agent, or browser holding valuable sessions requires the isolation, supply-chain pinning, and authorization changes described in this report before deployment.

Research record

10Evidence, objects, and sources

The material below preserves the identifiers and references used in this report.

10.1Research objects

Products, actors, techniques, affected objects, and control points discussed in the report.

npm package@jshookmcp/jshook

The audited registry package; pin an exact version and integrity, and reject the mutable latest tag

Pinned source commitbb79e43d60ffcd9fa3e330825f6e9efb0006d790

Current master snapshot used for first-party source and runtime-boundary analysis

Release commitcde13ed54517cca1a27a90d52a8824789294bcbb

Lightweight v0.3.4 tag and successful publish-workflow head

npm SHA-190b95d7fe21d9fde8a1593c9c4a4479ba1d96cea

Registry digest for the statically inspected 0.3.4 tarball

VulnerabilityCVE-2026-49856

Private-network ICMP and traceroute authorization bypass, fixed from 0.3.2

Fix commit02111311f7bd0f86a7d7ef8538986594b3a18afa

First source and release commit applying shared authorization to both probe paths

Application state~/.jshookmcp/state

Default state root that can restore activated domains and other runtime context

Legacy webhook port18789

Default second listener started when the legacy extension-registry domain activates

10.2Event chronology

  1. Repository created

    GitHub records the repository's creation; the first source commit followed on February 23.

  2. ICMP and traceroute introduced

    Commit b5e3b00f added the two network tools without the existing private-target authorization path.

  3. First affected npm artifact

    Version 0.2.9 became the first inspected publication containing the vulnerable probe mechanism.

  4. Private-network probe fixed

    Commit 02111311, tag v0.3.2, npm 0.3.2, and the repository advisory closed the default private-range bypass.

  5. GitHub-reviewed advisory published

    The global record assigned CVE-2026-49856, CVSS 4.3 and CWE-918, while listing only 0.3.1 affected.

  6. Scoped probe authorization exposed

    Commit bd05892d added the public authorization schema later shipped in 0.3.4.

  7. npm 0.3.4 published

    The latest registry package was published from the successful tag workflow and retained the network guard.

  8. SOSEC audit cutoff

    Source, npm artifacts, release history, public advisories, issues, community claims, and privileged call paths were frozen for this report.

10.3Sources and material

  1. vmoranv/jshookmcp repositoryhttps://github.com/vmoranv/jshookmcp
  2. Pinned source commit bb79e43dhttps://github.com/vmoranv/jshookmcp/commit/bb79e43d60ffcd9fa3e330825f6e9efb0006d790
  3. v0.3.4 release commit cde13ed5https://github.com/vmoranv/jshookmcp/commit/cde13ed54517cca1a27a90d52a8824789294bcbb
  4. npm package @jshookmcp/jshookhttps://www.npmjs.com/package/@jshookmcp/jshook
  5. npm 0.3.4 registry tarballhttps://registry.npmjs.org/@jshookmcp/jshook/-/jshook-0.3.4.tgz
  6. GitHub Actions v0.3.4 publish runhttps://github.com/vmoranv/jshookmcp/actions/runs/29432085723
  7. Pinned package manifesthttps://github.com/vmoranv/jshookmcp/blob/bb79e43d60ffcd9fa3e330825f6e9efb0006d790/package.json
  8. Published postinstall sourcehttps://github.com/vmoranv/jshookmcp/blob/cde13ed54517cca1a27a90d52a8824789294bcbb/scripts/postinstall.cjs
  9. GitHub Advisory GHSA-c5r6-m4mr-8q5j / CVE-2026-49856https://github.com/advisories/GHSA-c5r6-m4mr-8q5j
  10. Repository security advisoryhttps://github.com/vmoranv/jshookmcp/security/advisories/GHSA-c5r6-m4mr-8q5j
  11. Private-network probe fix commithttps://github.com/vmoranv/jshookmcp/commit/02111311f7bd0f86a7d7ef8538986594b3a18afa
  12. Sharp/libvips advisory GHSA-f88m-g3jw-g9cjhttps://github.com/advisories/GHSA-f88m-g3jw-g9cj
  13. protobufjs denial-of-service advisory GHSA-j3f2-48v5-ccwwhttps://github.com/advisories/GHSA-j3f2-48v5-ccww
  14. npm provenance documentationhttps://docs.npmjs.com/generating-provenance-statements/
  15. npm trusted publishing documentationhttps://docs.npmjs.com/trusted-publishers/
  16. Model Context Protocol security best practiceshttps://modelcontextprotocol.io/docs/tutorials/security/security_best_practices
  17. Model Context Protocol trust model and security policyhttps://github.com/modelcontextprotocol/modelcontextprotocol/security
  18. MCP tool annotations as risk vocabularyhttps://blog.modelcontextprotocol.io/posts/2026-03-16-tool-annotations/
  19. jshookmcp issue #10https://github.com/vmoranv/jshookmcp/issues/10
  20. jshookmcp PR #11https://github.com/vmoranv/jshookmcp/pull/11
  21. jshookmcp issue #44https://github.com/vmoranv/jshookmcp/issues/44
  22. jshookmcp issue #77https://github.com/vmoranv/jshookmcp/issues/77
  23. LINUX DO antivirus report discussionhttps://linux.do/t/topic/2037967
  24. LINUX DO process and CPU discussionhttps://linux.do/t/topic/1789318
  25. Maintainer discussion of large AI-generated pull requestshttps://linux.do/t/topic/2052535?tl=en