Back to skill

Security audit

NodeJS

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Node.js guidance skill, but some debugging instructions can expose secrets and its scoped user-memory behavior deserves review before use.

Review this skill before installing if you work on production systems. Do not run or share raw environment dumps or Node diagnostic reports unless secrets are redacted and the files are access-controlled. Be aware that the skill may read and maintain scoped preference or memory files under ~/Clawic/data/nodejs/.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
debug.md:32
Finding

Complete Environment Dump Can Expose Production Credentials

Content
View full analysis
Remediation
View remediation
[ name, { present: process.env[name] !== undefined, value: name === 'NODE_ENV' || name === 'PORT' || name === 'LOG_LEVEL' ? process.env[name] : '[REDACTED]' } ]) ); console.log(result); ``` For configuration drift, compare the resulting key set and validation status rather than complete environment contents. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
commands.md:59
Finding

Production Diagnostic Reports May Persist Environment Secrets Without Access Controls

Content
View full analysis
# write a report from a healthy process ``` The JSON report holds the JS and native stacks, resource usage, libuv handles, environment, and shared libraries at the moment of failure — the only artifact that survives an OOM abort with useful content. Turn it on in production before you need it. ``` ### Technical Analysis The Skill recommends enabling Node diagnostic reports in production and explicitly states that the generated JSON includes the process environment. Environment variables may contain credentials and other sensitive configuration. The guidance specifies a persistent report directory but does not require restrictive directory or file permissions, retention limits, secure deletion, collection restrictions, or sanitization before sharing. As a result, reports can become plaintext credential-bearing artifacts accessible to other local users, container-side collectors, backup systems, or support workflows. Generating diagnostic reports is legitimate for the declared debugging functionality. The security weakness is the lack of least-privilege storage and handling controls for reports known to contain sensitive information. ### Attack Path 1. An operator enables the recommended diagnostic-report flags in production. 2. A fatal error or `SIGUSR2` causes Node to write a report under `/var/log/node`. 3. The report contains environment variables and sensitive process details. 4. The report remains on disk or is collected by a log, backup, or support system. 5. A local user, sidecar, collector, or support recipient with access to that artifact reads th ...[truncated 606 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (14)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · commands.md (reported line 71)May include surrounding context.

Runtime Behavior Without Editing Code

bash
node --env-file=.env app.js               # node >=20.6, no dotenv dependency
node --watch app.js                       # restart on change (node >=22 stable)
node --run build                          # run a package.json script without the package-manager wrapper
UV_THREADPOOL_SIZE=16 node app.js         # libuv pool (SKILL.md rule 3); must be set before the process starts

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · memory-template.md (reported line 13)May include surrounding context.

md
last: YYYY-MM-DD

## Context
<!-- Runtime version, framework, database client, hosting target -->
<!-- Repository shape: single package, workspaces, monorepo -->

## Recurring Failures

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime.md (reported line 13)May include surrounding context.

md
- Upgrade at the LTS boundary, not at the EOL date: skipping to a fresh Current major puts you on a runtime that changes under you every two weeks.
- Pin the runtime in three places or they drift: `engines` in package.json (declares intent, warns on install), a `.nvmrc`/`.node-version` file (developers), and the container base image tag (production). All three should say the same major.
- `engines` is advisory for npm by default; `engine-strict=true` in `.npmrc` makes a mismatch fail the install instead of printing a warning nobody reads.
- Minimum-version claims in code and docs get verified against the Version Gates table in SKILL.md — that table is the single home for those numbers.

## Flags and NODE_OPTIONS

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Line L10 states that oversized delays overflow and fire immediately. In Node.js, delays larger than the allowed range are generally clamped to a small value rather than preserving the requested far-future timing; describing this as an immediate-fire overflow is materially misleading documentation about runtime behavior.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · cli.md (reported line 29)May include surrounding context.

Data on stdout, everything else on stderr. Progress bars, spinners, warnings, and log lines go to stderr; only the artifact the user asked for goes to stdout. That single rule is what makes mytool --json | jq work.

  • process.stdout.isTTY is undefined when piped or redirected: switch off colors, spinners, and interactive prompts when it is falsy. Respect NO_COLOR and FORCE_COLOR — users have set them for a reason.
  • EPIPE: when the reader closes early (mytool | head -3), the next write errors. Unhandled, it crashes with a stack the user did not cause. Handle it and exit quietly:
js
process.stdout.on('error', (err) => { if (err.code === 'EPIPE') process.exit(0); throw err; });

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The diagnostic report commands are legitimate troubleshooting guidance, but Node.js reports can capture sensitive environment variables, process arguments, filesystem paths, loaded libraries, and runtime state. In a security skill context, omitting an explicit privacy warning is a real information-exposure risk because users may enable reports in production and then store or share the artifacts insecurely.

Content

No source excerpt is available for this finding.

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · filesystem.md (reported line 48)May include surrounding context.

md
- `mkdir(p, { recursive: true })` is idempotent — no need to check existence first, and the check itself is a race.
- Do not test existence before acting: `existsSync` then `readFile` is a TOCTOU race and doubles the syscalls. Act and handle `ENOENT`.
- `readdir(p, { withFileTypes: true })` returns Dirents, saving a `stat` per entry — on directories with thousands of files that is the difference between one syscall and thousands. `{ recursive: true }` (node >=20) walks the tree without a manual recursion.
- `stat` follows symlinks, `lstat` does not. Walking a tree with `stat` and following links can loop forever.
- File times are unreliable as change detection: coarse granularity on some filesystems, and copies/checkouts rewrite them. Hash content when correctness matters.

## Watching

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · http.md (reported line 28)May include surrounding context.

md
- Per-origin concurrency is capped by the agent/dispatcher, not by your `Promise.all` — issuing 5k requests just queues 5k promises in memory. Cap at the source (SKILL.md rule 4).
- Timeouts on every outbound call: `fetch(url, { signal: AbortSignal.timeout(3000) })`. A hung upstream with no deadline holds a socket, a descriptor, and one of your request slots until the process restarts.
- Proxies: global `fetch` ignores `HTTP_PROXY`/`HTTPS_PROXY` by default. Set an undici `ProxyAgent` as the global dispatcher when the environment requires one; corporate TLS interception additionally needs the root CA (`NODE_EXTRA_CA_CERTS=/path/ca.pem`).
- `NODE_TLS_REJECT_UNAUTHORIZED=0` disables certificate verification process-wide, including calls you did not write. It is never the fix — install the CA instead.

## Retries That Help Instead Of Hurt

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Content

Scanner excerpt · packages.md (reported line 16)May include surrounding context.

md
- Production images: `npm ci --omit=dev` — devDependencies inflate image size and audit surface for code that never runs.
- The lockfile is a reviewable artifact. A diff that changes a hundred transitive versions in a PR about a typo means someone ran a bare `npm install` on a stale branch; regenerate deliberately rather than merging it.
- Merge conflicts in a lockfile are resolved by regenerating, not by hand-editing: take the incoming package.json, delete the lockfile, install, commit. Hand-merged lockfiles produce trees that exist on no machine.
- Install scripts run arbitrary code from every transitive dependency at install time. `npm ci --ignore-scripts` where the build tolerates it removes the largest supply-chain surface; native modules are the usual reason it cannot (→ `runtime.md`).
- `peerDependencies` auto-install since npm 7 — and auto-conflict; when two majors of one package coexist, `npm ls <pkg>` shows which dependency paths pulled each.
- `overrides` (npm >=8.3) pins a transitive dependency — the surgical fix for a vulnerability three levels deep. `npm audit fix --force` is the sledgehammer: major bumps, silent breakage.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The setup instructs the agent to read from and write to persistent files in the user's home directory (~/Clawic/data/nodejs/...) that are not necessary for a one-off Node.js code analysis task. This creates cross-session data access and persistence without clear user consent, which can expose unrelated personal or project context and cause unintended retention of user data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file directs silent access to user-home preference files and says to 'proceed without comment' if memory files are absent, while also recording future user statements back to disk. Performing these reads and writes without any user-facing warning or consent undermines transparency and can surprise users with hidden collection and persistence of preferences or contextual data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The guidance states 'CI runs UTC' and instructs users to 'Pin TZ in both places,' which imposes a locale/timezone choice in natural language. This can conflict with organizational language/locale policies when no user choice or explicit justification is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.