registry  /  paqad-ai  /  1.36.0

paqad-ai@1.36.0

Spec-driven development framework — AI agents that think before they type

AI Security Review

scanned 4h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malicious attack surface from install/import. The package is an AI-agent framework that, when explicitly onboarded, installs first-party project hooks and can later self-update globally from npm.

Static reason
One or more suspicious static signals were detected.
Trigger
npm install postinstall for chmod; user-invoked paqad-ai onboard/update for agent hooks; later agent SessionStart for silent update
Impact
Can modify project .paqad and agent config files after onboarding and can run npm global self-update in the background; no credential theft or unconsented install-time agent hijack confirmed.
Mechanism
first-party agent extension hooks plus background self-update
Policy narrative
Install-time behavior is limited to making packaged runtime scripts executable. The risk appears after a user runs paqad-ai onboarding/update: the CLI writes first-party AI-agent hook configuration for Claude/Codex and includes a SessionStart hook that can silently update paqad-ai globally from npm, then refresh project artifacts. This is broad agent lifecycle functionality but package-aligned and user-invoked rather than a malicious npm lifecycle hijack.
Rationale
Static inspection shows agent-control and background update capabilities, but they are part of a declared AI-agent framework and are not planted during npm postinstall. Because the package installs executable agent hooks and a silent updater after onboarding, warn rather than block.
Evidence
package.jsonruntime/scripts/postinstall.mjsruntime/hooks/silent-update.mjsdist/cli/index.jsruntime/hooks/**runtime/scripts/**.claude/settings.json.codex/hooks.json.paqad/framework-version.txt.paqad/logs/auto-update.log.paqad/locks/update.lock
Network endpoints2
npm view paqad-ai versionnpm install -g paqad-ai@latest

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • package.json runs postinstall: node runtime/scripts/postinstall.mjs
  • runtime/scripts/postinstall.mjs chmods shipped runtime hooks/scripts executable at install time
  • dist/cli/index.js wires user-invoked onboarding/update into .claude/settings.json and .codex/hooks.json hook surfaces
  • runtime/hooks/silent-update.mjs can spawn detached shell command: npm install -g paqad-ai@latest && paqad-ai update --silent
  • runtime/hooks/silent-update.mjs checks npm via execFileSync('npm',['view','paqad-ai','version'])
Evidence against
  • Postinstall only chmods files under the package runtime directory; it does not write project/home agent config
  • Agent hook/config writes are in CLI onboarding/update flow, not npm install-time execution
  • Network/update behavior is package-aligned self-update and is gated by paqad config/disabled checks
  • Scanner metadata/169.254 hits are security review reference text, not live package metadata access
  • Secrets code redacts OPENAI_API_KEY/VOYAGE_API_KEY and .paqad/secrets.env values rather than exfiltrating them
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsMinifiedObfuscatedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 42 file(s), 4.23 MB of source, external domains: 127.0.0.1, api.cohere.com, api.osv.dev, in-toto.io, paqad.ai, react.dev, www.w3.org

Source & flagged code

13 flagged · loading source
package.jsonView file
scripts.postinstall = node runtime/scripts/postinstall.mjs
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node runtime/scripts/postinstall.mjs
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.mdView file
13patternName = private_key_ec severity = critical line = 13 matchedText = -----BEG...----
Critical
Critical Secret

Package contains a critical-looking secret pattern.

runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.mdView on unpkg · L13
11patternName = private_key_rsa severity = critical line = 11 matchedText = -----BEG...----
Critical
Secret Pattern

RSA private key in runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md

runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.mdView on unpkg · L11
12patternName = private_key_rsa severity = critical line = 12 matchedText = -----BEG...----
Critical
Secret Pattern

RSA private key in runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md

runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.mdView on unpkg · L12
13patternName = private_key_ec severity = critical line = 13 matchedText = -----BEG...----
Critical
Secret Pattern

EC private key in runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md

runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.mdView on unpkg · L13
dist/rule-scripts/index.jsView file
506// src/rule-scripts/execute.ts L507: import { spawnSync } from "child_process"; L508: import { accessSync, constants, statSync } from "fs";
High
Child Process

Package source references child process execution.

dist/rule-scripts/index.jsView on unpkg · L506
1369import { join as join9 } from "path"; L1370: import { execa } from "execa"; L1371: async function loadChangeEvidence(projectRoot) {
High
Shell

Package source references shell execution.

dist/rule-scripts/index.jsView on unpkg · L1369
runtime/graph-ui/assets/index-B7e9pFJw.jsView file
218`;v(ke),Q(pt=>pt+1),le.file.exists&&!le.placeholder&&m(!0)}).catch(le=>n(le instanceof Error?le.message:String(le))),Pi().then(le=>{s(le.projectName),c(le.frameworkVersion)}).catch... L219: `),Q(Fe=>Fe+1),te()},se=_.useCallback(le=>{P||!p||(R(!0),W(null),G(null),ee(null),oR({content:O,baseHash:le!==void 0?le:x}).then(ke=>{if(ke.status==="ok"){S(ke.result.hash),e(Fe=>F... L220: In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Wl(i,e){return DB(i)||zB(i,e)||ZA(i,e)||XB()}var uO={black:"#000000",silver:"#C0C0C0",...
Medium
Dynamic Require

Package source references dynamic require/import behavior.

runtime/graph-ui/assets/index-B7e9pFJw.jsView on unpkg · L218
dist/index.jsView file
523} L524: function layeredConfigMap(projectRoot, env = process.env) { L525: const merged = /* @__PURE__ */ new Map(); ... L1944: try { L1945: const parsed = JSON.parse(trimmed); L1946: if (typeof parsed === "object" && parsed !== null && (parsed.type === "sk[redacted]" || parsed.type === "sk[redacted]")) { ... L2910: }, L2911: frozenMetadata: { L2912: type: "object", ... L4038: default_command: { type: "string" }, L4039: output_source: { type: "string", enum: ["stdout", "file"] }, L4040: output_path_pattern: { type: "string" }
High
Cloud Metadata Access

Source reaches cloud instance metadata or link-local credential endpoints.

dist/index.jsView on unpkg · L523
523} L524: function layeredConfigMap(projectRoot, env = process.env) { L525: const merged = /* @__PURE__ */ new Map(); ... L1944: try { L1945: const parsed = JSON.parse(trimmed); L1946: if (typeof parsed === "object" && parsed !== null && (parsed.type === "sk[redacted]" || parsed.type === "sk[redacted]")) { ... L2910: }, L2911: frozenMetadata: { L2912: type: "object", ... L4038: default_command: { type: "string" }, L4039: output_source: { type: "string", enum: ["stdout", "file"] }, L4040: output_path_pattern: { type: "string" }
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/index.jsView on unpkg · L523
runtime/hooks/silent-update.mjsView file
347const out = openSync(logPath, 'a'); L348: const child = spawn('npm install -g paqad-ai@latest && paqad-ai update --silent', { L349: shell: true,
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

runtime/hooks/silent-update.mjsView on unpkg · L347
runtime/capabilities/security/skills/auth-mechanism-review/scripts/scan-auth-smells.shView file
path = [redacted]-mechanism-review/scripts/scan-auth-smells.sh kind = build_helper sizeBytes = 1583 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

runtime/capabilities/security/skills/auth-mechanism-review/scripts/scan-auth-smells.shView on unpkg

Findings

4 Critical5 High6 Medium6 Low
CriticalCritical Secretruntime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md
CriticalSecret Patternruntime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md
CriticalSecret Patternruntime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md
CriticalSecret Patternruntime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/rule-scripts/index.js
HighShelldist/rule-scripts/index.js
HighCloud Metadata Accessdist/index.js
HighRuntime Package Installruntime/hooks/silent-update.mjs
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requireruntime/graph-ui/assets/index-B7e9pFJw.js
MediumNetwork
MediumEnvironment Vars
MediumShips Build Helperruntime/capabilities/security/skills/auth-mechanism-review/scripts/scan-auth-smells.sh
MediumStructural Risk Force Deep Review
LowScripts Present
LowWeak Cryptodist/index.js
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings