# nomicfoundation.hardhat-solidity@0.9.3 security report (VS Code Marketplace)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-11-10T18:32:52.000Z
- Files reviewed: 70
- Files not reviewed: 2 files (too large)
- Findings: 6 medium, 12 low severity findings
- Report: https://security.togoder.click/vscode/nomicfoundation.hardhat-solidity
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the VS Code Marketplace package nomicfoundation.hardhat-solidity@0.9.3 on Nov 10, 2026. An AI review of 70 source files produced 6 medium, 12 low severity findings. The overall verdict is medium: the findings flag risky but common patterns that the package's purpose explains (dynamic code, telemetry, native installers, broad file or network access), not malware. 2 files were not reviewed (too large); the verdict covers only the reviewed files.

## Findings

### [medium] environment and filesystem capability exposure

Finding ID: `NPS-693D87A5323C`

File: `server/node_modules/@nomicfoundation/slang/wasm/generated/solidity_cargo_wasm.component.js:194`

The WASM shim exposes getEnvironment() to the sandboxed Wasm module, allowing it to read process environment variables. This is standard boilerplate emitted by jco/componentize-js for the WASI preview2 preview1-adapter and is required for the Solidity parser runtime to function; the env is only marshalled into Wasm linear memory, not sent anywhere.

### [medium] filesystem preopen handles

Finding ID: `NPS-1A3D5EF1E7D1`

File: `server/node_modules/@nomicfoundation/slang/wasm/generated/solidity_cargo_wasm.component.js:1600`

getDirectories() and Descriptor write/stat operations expose preopened filesystem descriptors to the Wasm module. Again this is generated WASI glue, not authored code, and no reading of credentials or scanning of sensitive paths (SSH keys, browser data, tokens) occurs in this file.

### [medium] wasi-environment-and-filesystem-imports

Finding ID: `NPS-B0DF55845912`

File: `server/node_modules/@nomicfoundation/slang/wasm/generated/solidity_cargo_wasm.component.js:5950`

The WASM component imports WASI environment (environ_get/environ_sizes_get), filesystem preopens, stdout/stderr and random_get. These are the standard WASI host interfaces generated by the component toolchain (jco/wit-bindgen) for a Rust-compiled WebAssembly module; the module is the Slang Solidity parser, which needs environment/stdout plumbing and randomness from the WASI runtime. No env vars, file contents, or secrets are read or transmitted by this glue code — the imports are just wired through to the embedded WASM core.

### [medium] native addon loader

Finding ID: `NPS-C601A97FA9D1`

File: `server/node_modules/@nomicfoundation/solidity-analyzer/index.js`

Standard napi-rs platform/arch switch that loads the matching prebuilt .node native binding for solidity-analyzer, falling back to per-platform npm packages. This is the conventional native-addon loader pattern and fits the package's purpose of parsing/analyzing Solidity sources.

### [medium] child_process execSync ('which ldd')

Finding ID: `NPS-F6A55EA6041C`

File: `server/node_modules/@nomicfoundation/solidity-analyzer/index.js:11`

Runs 'which ldd' only on old Node versions lacking process.report to detect musl vs glibc; a benign, fixed command with no user input and no network or data exfiltration.

### [medium] dynamic-require

Finding ID: `NPS-185F38D90212`

File: `server/out/worker/WorkerProcess.js`

The worker resolves the user's locally installed hardhat module (require.resolve with paths: [process.cwd()]) and requires register.js and hardhat-lib.js. This is exactly the worker-process bootstrap the extension needs to build Hardhat compilation inputs, not remote code loading.

### [low] native-addon loader

Finding ID: `NPS-E6F92F59847F`

File: `server/node_modules/@bytecodealliance/jco-node-fs/index.js`

napi-rs auto-generated loader that selects the right prebuilt .node binary for the platform and requires it. Requiring a native addon by path or optional-dependency package is exactly what this generated boilerplate is for and does not execute code from an unexpected external destination.

### [low] env-controlled library path

Finding ID: `NPS-93401C8D0CD1`

File: `server/node_modules/@bytecodealliance/jco-node-fs/index.js`

NAPI_RS_NATIVE_LIBRARY_PATH, NAPI_RS_FORCE_WASI, and NAPI_RS_ENFORCE_VERSION_CHECK are read to influence which binding loads. These are documented napi-rs override flags and are user-set, not attacker-supplied; loading a path the user explicitly set is not exfiltration or remote code execution.

### [low] child_process execSync

Finding ID: `NPS-B3FC44F98AC0`

File: `server/node_modules/@bytecodealliance/jco-node-fs/index.js`

Runs `ldd --version` to detect musl libc on Linux. This is a standard, hardcoded detection probe used only for choosing the correct prebuilt binary; no user input reaches the command, and no data is sent anywhere.

### [low] network-capable shim

Finding ID: `NPS-3BC5A924A388`

File: `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/http.js`

This file implements the WASI preview2 HTTP interface (outgoing/incoming handlers) on top of globalThis.fetch. Making network requests via fetch is the entire purpose of an HTTP shim; URLs and headers come from the calling WASI component, not from hardcoded exfiltration endpoints. No secrets, env vars, credentials or workspace data are read or sent.

### [low] in-memory socket emulation

Finding ID: `NPS-39C212F458B8`

File: `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/in-memory-sockets.js`

This file implements the browser-side, process-local emulation of TCP/UDP sockets for the @bytecodealliance/preview2-shim WASI/webassembly component runtime. Connections and datagrams are held in JavaScript Maps and never touch the real network, filesystem, child processes, or environment variables; there is no obfuscation, no remote code loading, and no credential access.

### [low] UDP socket capability

Finding ID: `NPS-4368C23592DA`

File: `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-socket-udp.js`

Implements WASI preview2 UDP socket shim (bind, connect, send/receive datagrams, buffer/TTL options) on top of node:dgram. This is the entire, expected purpose of @bytecodealliance/preview2-shim; no credential access, exfiltration, obfuscation, or hidden triggers are present.

### [low] worker_threads / sync bridging

Finding ID: `NPS-FAD07441AAF5`

File: `server/node_modules/@bytecodealliance/preview2-shim/dist/synckit/index.js`

This is the upstream synckit library (untouched, with original UnTS MIT license header) that bridges async worker threads into a synchronous function using MessageChannel, SharedArrayBuffer and Atomics.wait. It spawns a worker thread only via a caller-supplied createWorker factory with empty execArgv; there is no network access, no filesystem/credential reading, no eval of remote payloads and no hidden or date/host-gated logic. Worker-based sync execution is exactly what synckit is built for (used by preview2-shim within Hardhat's Solidity tooling).

### [low] standard WASI glue / no obfuscation

Finding ID: `NPS-B07273DA424B`

File: `server/node_modules/@nomicfoundation/slang/wasm/generated/solidity_cargo_wasm.component.js:1`

Names like trampolineNN and the resource handle tables are the mechanical output of a WebAssembly component toolchain (jco), not deliberate obfuscation; there are no encoded blobs, no remote downloads, no child-process spawning, and no network calls to any host in this portion. The file is a Solidity parser/lexer binding consistent with the hardhat-solidity extension.

### [low] dynamic require of CLI argument

Finding ID: `NPS-0EA09A5D0DBA`

File: `server/out/ConfigLoader.js:9`

The file requires the module path given as argv[2] and sends the result to the parent process via process.send. This is the extension's ConfigLoader helper, intended to load a Truffle/Hardhat config file on behalf of the extension host; loading a user-specified config path is the file's whole purpose, not exfiltration. The leading IIFE only sets a Sentry debug-id on the error stack (standard bundler instrumentation) and does nothing covert.

### [low] Sentry debug-id instrumentation

Finding ID: `NPS-801C9CB29D45`

File: `server/out/hardhat.config.js:2`

The IIFE at the top attaches a Sentry debug ID to the global Error object; this is a standard build-time instrumentation snippet (esbuild/rollup Sentry plugin) used for error source mapping, not data collection or exfiltration.

### [low] process-messaging

Finding ID: `NPS-129027215C24`

File: `server/out/worker/WorkerProcess.js`

Uses process.on('message')/process.send IPC with the parent extension host to answer file-belongs, resolve-import, and build-compilation requests. Expected for a child worker of a VS Code extension.

### [low] sentry-bootstrap

Finding ID: `NPS-25EC0B386A84`

File: `server/out/worker/WorkerProcess.js:2`

Standard Sentry debug-id injection into the global object for source-map correlation. No data is read or transmitted; it only registers a hash. Normal for bundled extensions built with Sentry tooling.

## Files reviewed

- `server/node_modules/@nomicfoundation/slang/wasm/generated/solidity_cargo_wasm.component.js` (medium): 4 findings
- `server/node_modules/@nomicfoundation/solidity-analyzer/index.js` (medium): 2 findings
- `server/out/worker/WorkerProcess.js` (medium): 3 findings
- `server/node_modules/@bytecodealliance/jco-node-fs/index.js` (low): 3 findings
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/http.js` (low): 1 finding
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/in-memory-sockets.js` (low): 1 finding
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-socket-udp.js` (low): 1 finding
- `server/node_modules/@bytecodealliance/preview2-shim/dist/synckit/index.js` (low): 1 finding
- `server/out/ConfigLoader.js` (low): 1 finding
- `server/out/hardhat.config.js` (low): 1 finding
- `package.json` (safe): Clear
- `server/node_modules/@bytecodealliance/jco-node-fs-linux-x64-gnu/package.json` (safe): Clear
- `server/node_modules/@bytecodealliance/jco-node-fs/package.json` (safe): Clear
- `server/node_modules/@bytecodealliance/jco-node-fs/wrapper.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/cli.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/clocks.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/common.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/config.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/environment.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/filesystem.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/in-memory-filesystem.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/in-memory-http.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/index.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/io.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/random.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/browser/sockets.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/common/instantiation.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/calls.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-filesystem.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-http.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-io.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-socket-tcp.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-sockets.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-thread.bundle.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/io/worker-thread.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/cli.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/clocks.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/filesystem.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/http.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/index.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/io.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/random.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/dist/nodejs/sockets.js` (safe): Clear
- `server/node_modules/@bytecodealliance/preview2-shim/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/ast/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/ast/nodes.generated.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/bindings/assertions.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/bindings/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/compilation/builder.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/compilation/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/cst/assertions.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/cst/extensions.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/cst/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/cst/rewriter.generated.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/parser/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/target/utils/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/slang/wasm/index.mjs` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-darwin-x64/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc/package.json` (safe): Clear
- `server/node_modules/@nomicfoundation/solidity-analyzer/package.json` (safe): Clear

## Files not reviewed

Not covered by the verdict above.

- `out/extension.js`: Not reviewed: file too large (2231KB > 1024KB)
- `server/out/index.js`: Not reviewed: file too large (27143KB > 1024KB)

AI analysis is guidance, not a guarantee. Methodology: https://security.togoder.click/methodology
