registry  /  @portel/photon  /  1.36.1

@portel/photon@1.36.1

Build MCP servers, CLI tools, and web dashboards for AI agents from a single TypeScript file.

AI Security Review

scanned 2h ago · by lpm-firewall-ai

The package changes the current repository's Git hooks path through its `prepare` lifecycle script. Separate explicit CLI commands can generate a first-party Claude plugin or register a Photon MCP server in Claude Desktop. No credential exfiltration, remote payload execution, or stealth persistence was confirmed.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
Lifecycle `prepare`; explicit `photon maker sync --claude-code` or `photon mcp install <name>` commands.
Impact
Can redirect repository hook lookup and add Photon-controlled commands/configuration after user-invoked setup.
Mechanism
Git hook-path mutation and explicit AI-client extension/config generation.
Rationale
The lifecycle Git configuration mutation warrants a warning under the stated prepare-only hook policy. The AI-agent configuration behavior is explicit-user-command or first-party extension setup, not unconsented install-time hijacking.
Evidence
package.jsonbin/photondist/cli.jsdist/claude-code-plugin.jsdist/cli/commands/mcp.jsdist/shared/sqlite-runtime.js.git/config.claude-plugin/hooks.json.claude-plugin/scripts/check-photon.sh

Decision evidence

public snapshot
AI called this Suspicious at 88.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • package.json: `prepare` runs `git config core.hooksPath .githooks || true` during lifecycle execution.
  • dist/claude-code-plugin.js can generate a Claude SessionStart hook that globally installs `@portel/photon` if absent.
  • dist/cli/commands/mcp.js can rewrite Claude Desktop MCP config, but only through explicit `photon mcp install <name>`.
  • No shipped `.githooks` assets were found, so the lifecycle config can still alter a repository hook path.
Evidence against
  • package.json has no `preinstall`, `install`, or `postinstall` hook.
  • bin/photon and dist/cli.js only launch the CLI; they do not perform import-time harvesting or network activity.
  • dist/cli/commands/mcp.js wires config mutation solely to the explicit nested `mcp install` command.
  • dist/claude-code-plugin.js is invoked only by explicit `photon maker sync --claude-code`; generated credential setup is interactive.
  • dist/template-manager.js blocks dangerous identifiers and shadows process/require/global globals around its templating evaluator.
  • dist/shared/sqlite-runtime.js dynamically loads only Bun SQLite or optional better-sqlite3; no remote payload source was found.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsMinifiedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 228 file(s), 3.94 MB of source, external domains: 127.0.0.1, a2ui.org, accounts.google.com, api.github.com, app.example.com, bun.sh, cdn.jsdelivr.net, cli.github.com, example.com, github.com, graph.microsoft.com, login.microsoftonline.com, modelcontextprotocol.io, nodejs.org, oauth2.googleapis.com, port.workers.dev, raw.githubusercontent.com, registry.npmjs.org, unpkg.com, www.apple.com, www.chartjs.org, www.googleapis.com, www.w3.org, youtube.com
Oversized source lightweight scan
dist/beam-ts-worker.js9.51 MB file, sampled 256 KB
FilesystemNetworkDynamicRequire
dist/beam.bundle.js3.75 MB file, sampled 256 KB
ChildProcessHighEntropyStringsMinifiedUrlStringsgithub.comwww.chartjs.orgwww.w3.org

Source & flagged code

9 flagged · loading source
dist/shared-utils.jsView file
7import { existsSync } from 'fs'; L8: import { execSync } from 'child_process'; L9: import * as path from 'path';
High
Child Process

Package source references child process execution.

dist/shared-utils.jsView on unpkg · L7
dist/cli/commands/build.jsView file
586if (isWindows) { L587: // PowerShell: must go in profile (no auto-discovery) L588: // Handled in step 5 below
High
Shell

Package source references shell execution.

dist/cli/commands/build.jsView on unpkg · L586
2Cross-file remote execution chain: dist/cli/commands/build.js spawns dist/auto-ui/bridge/index.js; helper contains network access plus dynamic code execution. L2: import fs from 'fs'; L3: import { spawn } from 'child_process'; L4: import ora from 'ora'; ... L10: import { encodeAssetForEmbed } from '../../shared/asset-encoding.js'; L11: const __dirname = path.dirname(fileURLToPath(import.meta.url)); L12: /** ... L278: catch { L279: spinner.fail('Bun is required for compilation. Install it: https://bun.sh'); L280: process.exit(1); ... L544: const homeDir = __os.default.homedir(); L545: const isWindows = process.platform === 'win32'; L546: const S = String.fromCharCode(36); // shell dollar sign
High
Cross File Remote Execution Context

Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.

dist/cli/commands/build.jsView on unpkg · L2
dist/template-manager.jsView file
181// eslint-disable-next-line @typescript-eslint/no-implied-eval L182: const fn = new Function(...keys, 'process', 'require', 'globalThis', 'global', 'return (' + expr + ')'); L183: return fn(...values, undefined, undefined, undefined, undefined);
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/template-manager.jsView on unpkg · L181
dist/shared/sqlite-runtime.jsView file
33// eslint-disable-next-line @typescript-eslint/no-explicit-any L34: const mod = await dynamicImport('bun:sqlite'); L35: cachedCtor = mod.Database;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/shared/sqlite-runtime.jsView on unpkg · L33
dist/cli-alias.jsView file
16const ALIAS_DIR = path.join(getDefaultContext().baseDir, 'bin'); L17: const IS_WINDOWS = process.platform === 'win32'; L18: const PATH_SEPARATOR = IS_WINDOWS ? ';' : ':'; ... L67: } L68: const script = `#!/bin/bash L69: # Auto-generated alias for photon: ${photonName} ... L94: async function checkAndInstructPath() { L95: const pathEnv = process.env.PATH || ''; L96: const paths = pathEnv.split(PATH_SEPARATOR); ... L102: if (IS_WINDOWS) { L103: logger.info(`\nTo add it permanently, run this in PowerShell (as Administrator):`); L104: logger.info(` [Environment]::SetEnvironmentVariable("Path", $env:Path + ";${ALIAS_DIR}", "User")`);
Medium
Install Persistence

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

dist/cli-alias.jsView on unpkg · L16
dist/cli/commands/dev.jsView file
172if (startLocalBackend) { L173: console.error(`⚙️ Starting Beam backend on http://localhost:${backendPort}...`); L174: const { startBeam } = await import('../../auto-ui/beam.js'); ... L184: const childEnv = { L185: ...process.env, L186: VITE_DAEMON_PORT: String(backendPort), L187: }; L188: const uiProcess = spawn(runCmd, runArgs, { L189: cwd: uiDir,
High
Same File Env Network Execution

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

dist/cli/commands/dev.jsView on unpkg · L172
dist/beam.bundle.jsView file
path = dist/beam.bundle.js kind = oversized_source_file sizeBytes = 3931139 magicHex = [redacted]
High
Oversized Source File

Package contains source files above the static scanner size ceiling.

dist/beam.bundle.jsView on unpkg
dist/auto-ui/beam.jsView file
matchType = previous_version_dangerous_delta matchedPackage = @portel/photon@1.36.0 matchedIdentity = npm:QHBvcnRlbC9waG90b24:1.36.0 similarity = 0.983 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

dist/auto-ui/beam.jsView on unpkg

Findings

1 Critical5 High5 Medium6 Low
CriticalPrevious Version Dangerous Deltadist/auto-ui/beam.js
HighChild Processdist/shared-utils.js
HighShelldist/cli/commands/build.js
HighSame File Env Network Executiondist/cli/commands/dev.js
HighCross File Remote Execution Contextdist/cli/commands/build.js
HighOversized Source Filedist/beam.bundle.js
MediumDynamic Requiredist/shared/sqlite-runtime.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/cli-alias.js
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/template-manager.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings