registry  /  @geraldmaron/construct  /  1.5.4

@geraldmaron/construct@1.5.4

Construct — agent orchestration layer for OpenCode, Claude Code, and other coding surfaces

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM blocks this version under the AI-agent control-surface policy. A downstream npm install automatically mutates the consumer project's AI-agent control surfaces. The hook stages a launcher and synchronizes Construct-managed adapters without an explicit setup command.

Static reason
High-risk behavior combination matched malicious policy.; source matched previously finalized malicious package; routed for review
Trigger
Installing the package in a downstream project containing `package.json`.
Impact
Creates or overwrites Construct launcher/configuration material under the consuming project, including AI-agent integration paths.
Mechanism
Postinstall project adapter and AI-agent configuration staging.
Policy narrative
On `npm install`, `bin/construct-postinstall.mjs` calls `stageProjectAdapters`, which creates `.construct` launcher files and runs `sync-specialists.mjs --project`. That sync script is designed to write project AI-agent adapter/configuration surfaces, including `.claude`, `.codex`, `.github`, and `.mcp.json`; the lifecycle hook also appends `.gitignore` and writes an install manifest. Although no credential theft or payload download was confirmed, this is unconsented postinstall mutation of a foreign/broad AI-agent control surface.
Rationale
Direct source inspection confirms an automatic postinstall chain that writes AI-agent configuration into consumer projects. This meets the provided policy's blocking condition regardless of noisy scanner similarity and secret-pattern hints.
Evidence
package.jsonbin/construct-postinstall.mjslib/install/stage-project.mjsscripts/sync-specialists.mjslib/hooks/scan-secrets.mjs.construct.construct/install-manifest.json.gitignore.claude.codex.github.mcp.json

Decision evidence

public snapshot
AI called this Malicious at 96.0% confidence as Malware with low false-positive risk.
Evidence for policy block
  • `package.json` runs `bin/construct-postinstall.mjs` on install.
  • `bin/construct-postinstall.mjs` automatically stages `.construct`, appends `.gitignore`, and writes an install receipt.
  • `lib/install/stage-project.mjs` executes `scripts/sync-specialists.mjs --project` during postinstall.
  • `scripts/sync-specialists.mjs` defines project writes to `.claude`, `.codex`, `.github`, and `.mcp.json` AI-agent integration surfaces.
Evidence against
  • Global install exits before machine-scope setup; user-scope setup requires an explicit `construct install --footprint=user`.
  • `lib/hooks/scan-secrets.mjs` detects and blocks local secret writes; no exfiltration is shown.
  • Flagged OpenRouter and telemetry paths are runtime features, not invoked by the postinstall chain.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 774 file(s), 5.56 MB of source, external domains: 127.0.0.1, api.anthropic.com, api.atlassian.com, api.github.com, api.githubcopilot.com, api.linear.app, api.openai.com, app.slack.com, astral.sh, d2lang.com, developer.1password.com, docs.docker.com, example.com, fonts.googleapis.com, generativelanguage.googleapis.com, github.com, graphviz.org, huggingface.co, json-schema.org, nodejs.org, ollama.com, opencode.ai, openrouter.ai, pandoc.org, raw.githubusercontent.com, schemas.openxmlformats.org, slack.com, www.apple.com, www.libreoffice.org, your-domain.atlassian.net

Source & flagged code

22 flagged · loading source
package.jsonView file
scripts.postinstall = node ./bin/construct-postinstall.mjs
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
lib/hooks/scan-secrets.mjsView file
47patternName = private_key_rsa severity = critical line = 47 matchedText = { name: .../ },
Critical
Critical Secret

Package contains a critical-looking secret pattern.

lib/hooks/scan-secrets.mjsView on unpkg · L47
47patternName = private_key_rsa severity = critical line = 47 matchedText = { name: .../ },
Critical
Secret Pattern

RSA private key in lib/hooks/scan-secrets.mjs

lib/hooks/scan-secrets.mjsView on unpkg · L47
51patternName = private_key_openssh severity = critical line = 51 matchedText = { name: .../ },
Critical
Secret Pattern

OpenSSH private key in lib/hooks/scan-secrets.mjs

lib/hooks/scan-secrets.mjsView on unpkg · L51
platforms/opencode/sync-config.mjsView file
6import fs from "node:fs"; L7: import { spawnSync } from "node:child_process"; L8: import { readOpenCodeConfig, writeOpenCodeConfig, findOpenCodeConfigPath } from "../../lib/opencode-config.mjs";
High
Child Process

Package source references child process execution.

platforms/opencode/sync-config.mjsView on unpkg · L6
templates/distribution/run.mjsView file
221' - Bootstrap a binary: ./.construct/bootstrap.sh (POSIX)\n' + L222: ' powershell -File .construct/bootstrap.ps1 (Windows)\n' L223: );
High
Shell

Package source references shell execution.

templates/distribution/run.mjsView on unpkg · L221
lib/deck-export-pptx.mjsView file
1345missing: ['pptxgenjs'], L1346: message: 'Install pptxgenjs to enable PPTX export (`npm install pptxgenjs` in the Construct package).', L1347: }; ... L1350: const payload = Buffer.from(JSON.stringify(opts)).toString('base64'); L1351: const child = spawnSync(process.execPath, [ L1352: '--input-type=module',
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

lib/deck-export-pptx.mjsView on unpkg · L1345
20L21: const require = createRequire(import.meta.url); L22: const MODULE_URL = pathToFileURL(fileURLToPath(import.meta.url)).href;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

lib/deck-export-pptx.mjsView on unpkg · L20
lib/document-assets.mjsView file
21import crypto from 'node:crypto'; L22: import { spawnSync } from 'node:child_process'; L23: L24: const REMOTE_REF = /^(?:https?:|data:)/i; L25: const HTTP_REF = /^https?:/i; ... L38: } catch { return null; } L39: const script = 'const u=process.argv[1],d=process.argv[2];fetch(u).then(r=>{if(!r.ok)process.exit(2);return r.arrayBuffer();}).then(b=>{require("node:fs").writeFileSync(d,Buffer.fr... L40: const res = spawnSync(process.execPath, ['-e', script, url, dest], { timeout: 20000 }); ... L114: L115: export function buildAssetManifest(doc, { baseDir = process.cwd() } = {}) { L116: const blocks = (doc?.sections || []).flatMap((section) => section.blocks || []);
Low
Weak Crypto

Package source references weak cryptographic algorithms.

lib/document-assets.mjsView on unpkg · L21
lib/embed/supervision.mjsView file
9* Linux — systemd user unit at ~/.config/systemd/user/construct-embed.service L10: * Windows — Task Scheduler (schtasks) entry named "Construct.Embed" L11: * ... L21: import path from 'node:path'; L22: import { spawnSync } from 'node:child_process'; L23: ... L25: L26: const HOME = os.homedir(); L27: const PLATFORM = process.platform; L28: const NODE_BIN = process.execPath; ... L34: const result = spawnSync('which', ['construct'], { encoding: 'utf8' }); L35: return result.status === 0 ? result.stdout.trim() : 'construct';
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

lib/embed/supervision.mjsView on unpkg · L9
lib/runtime/whisper-bootstrap.mjsView file
23import { existsSync, mkdirSync, statSync, createWriteStream } from 'node:fs'; L24: import { spawnSync } from 'node:child_process'; L25: import { pipeline } from 'node:stream/promises'; ... L30: L31: const HF_MODEL_BASE_URL = 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main'; L32: const DEFAULT_MODEL = process.env.CONSTRUCT_WHISPER_MODEL || 'base.en'; L33: const KNOWN_MODELS = new Set(['tiny', 'tiny.en', 'base', 'base.en', 'small', 'small.en', 'medium', 'medium.en', 'large-v3', 'large-v3-turbo']);
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

lib/runtime/whisper-bootstrap.mjsView on unpkg · L23
lib/mcp/tools/memory.mjsView file
14export async function memorySearch(args) { L15: const cwd = args.cwd ? resolve(String(args.cwd)) : process.cwd(); L16: const project = args.project || null; ... L28: try { L29: const hybrid = await buildHybridSearchResultsAsync(cwd, query, { limit, env: process.env }); L30: hybridResults = (hybrid.results || []).map((r) => ({ ... L177: const cloudId = process.env.ATLASSIAN_CLOUD_ID || 'hashicorp.atlassian.net'; L178: const res = await fetch(`https://api.atlassian.com/rovo/v1/search`, { L179: method: 'POST', ... L183: }, L184: body: JSON.stringify({ query, limit: topK }), L185: });
Critical
Credential Exfiltration

Source appears to send environment or credential material to an external endpoint.

lib/mcp/tools/memory.mjsView on unpkg · L14
lib/libreoffice-export.mjsView file
10import path from 'node:path'; L11: import { spawnSync } from 'node:child_process'; L12: ... L19: function whichBin(name, env) { L20: const cmd = process.platform === 'win32' ? 'where' : 'which'; L21: const result = spawnSync(cmd, [name], { encoding: 'utf8', env }); L22: if (result.status !== 0) return null; L23: return (result.stdout || '').trim().split('\n')[0] || null; L24: } L25: L26: export function resolveLibreOfficeBin(env = process.env, { existsSyncFn = fs.existsSync } = {}) { L27: const fromEnv = (env.CONSTRUCT_LIBREOFFICE_BIN || env.SOFFICE_BIN || '').trim();
High
Sandbox Evasion Gated Capability

Source gates dangerous network, credential, or execution behavior behind CI, host, platform, time, or geo fingerprint checks.

lib/libreoffice-export.mjsView on unpkg · L10
lib/document-extract/docling-sidecar.pyView file
path = lib/document-extract/docling-sidecar.py kind = build_helper sizeBytes = 6406 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

lib/document-extract/docling-sidecar.pyView on unpkg
templates/distribution/construct-reference.docxView file
path = [redacted]-reference.docx kind = high_entropy_blob sizeBytes = 11466 magicHex = [redacted]
High
Ships High Entropy Blob

Package ships high-entropy non-source blobs.

templates/distribution/construct-reference.docxView on unpkg
path = [redacted]-reference.docx kind = compressed_blob sizeBytes = 11466 magicHex = [redacted]
Medium
Ships Compressed Blob

Package ships compressed or archive-like blobs.

templates/distribution/construct-reference.docxView on unpkg
path = [redacted]-reference.docx kind = nested_archive_needs_inspection sizeBytes = 11466 magicHex = [redacted]
Low
Nested Archive Needs Inspection

Package ships a nested archive or MCP bundle that was inventoried but not recursively analyzed.

templates/distribution/construct-reference.docxView on unpkg
lib/mcp/memory-bridge.mjsView file
matchType = normalized_sha256 matchedPackage = @geraldmaron/construct@1.5.3 matchedPath = lib/mcp/memory-bridge.mjs matchedIdentity = npm:QGdlcmFsZG1hcm9uL2NvbnN0cnVjdA:1.5.3 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

lib/mcp/memory-bridge.mjsView on unpkg
lib/mcp/tools/telemetry.mjsView file
matchType = normalized_sha256 matchedPackage = @geraldmaron/construct@1.5.3 matchedPath = lib/mcp/tools/telemetry.mjs matchedIdentity = npm:QGdlcmFsZG1hcm9uL2NvbnN0cnVjdA:1.5.3 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

lib/mcp/tools/telemetry.mjsView on unpkg
lib/providers/secret-resolver.mjsView file
matchType = normalized_sha256 matchedPackage = @geraldmaron/construct@1.5.3 matchedPath = lib/providers/secret-resolver.mjs matchedIdentity = npm:QGdlcmFsZG1hcm9uL2NvbnN0cnVjdA:1.5.3 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

lib/providers/secret-resolver.mjsView on unpkg
lib/runtime/uv-bootstrap.mjsView file
matchType = normalized_sha256 matchedPackage = @geraldmaron/construct@1.5.3 matchedPath = lib/runtime/uv-bootstrap.mjs matchedIdentity = npm:QGdlcmFsZG1hcm9uL2NvbnN0cnVjdA:1.5.3 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

lib/runtime/uv-bootstrap.mjsView on unpkg
lib/distill.mjsView file
matchType = normalized_sha256 matchedPackage = @geraldmaron/construct@1.5.3 matchedPath = lib/distill.mjs matchedIdentity = npm:QGdlcmFsZG1hcm9uL2NvbnN0cnVjdA:1.5.3 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

lib/distill.mjsView on unpkg

Findings

4 Critical12 High7 Medium7 Low
CriticalCritical Secretlib/hooks/scan-secrets.mjs
CriticalCredential Exfiltrationlib/mcp/tools/memory.mjs
CriticalSecret Patternlib/hooks/scan-secrets.mjs
CriticalSecret Patternlib/hooks/scan-secrets.mjs
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processplatforms/opencode/sync-config.mjs
HighShelltemplates/distribution/run.mjs
HighSame File Env Network Executionlib/runtime/whisper-bootstrap.mjs
HighSandbox Evasion Gated Capabilitylib/libreoffice-export.mjs
HighRuntime Package Installlib/deck-export-pptx.mjs
HighShips High Entropy Blobtemplates/distribution/construct-reference.docx
HighKnown Malware Source Similaritylib/mcp/memory-bridge.mjs
HighKnown Malware Source Similaritylib/mcp/tools/telemetry.mjs
HighKnown Malware Source Similaritylib/providers/secret-resolver.mjs
HighKnown Malware Source Similaritylib/runtime/uv-bootstrap.mjs
HighKnown Malware Source Similaritylib/distill.mjs
MediumDynamic Requirelib/deck-export-pptx.mjs
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencelib/embed/supervision.mjs
MediumShips Build Helperlib/document-extract/docling-sidecar.py
MediumShips Compressed Blobtemplates/distribution/construct-reference.docx
MediumStructural Risk Force Deep Review
LowScripts Present
LowEval
LowWeak Cryptolib/document-assets.mjs
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNested Archive Needs Inspectiontemplates/distribution/construct-reference.docx