SkyKoi — Koi runtime. Multi-channel gateway CLI with RPC Koi.
AI Security Review
scanned 1mo ago · by lpm-firewall-ai
This is conditional credential exposure to an unrestricted configured endpoint, not evidence of covert malware or install-time execution. The package has no npm install lifecycle hook.
Run the skykoi login command with a token while an alternate platform URL is selected.
Impact
A misconfigured or malicious runtime environment could receive the supplied service token.
Mechanism
Forwards a bearer token to a configurable platform endpoint.
AI rationale
This is conditional credential exposure to an unrestricted configured endpoint, not evidence of covert malware or install-time execution. The package has no npm install lifecycle hook.
6Cross-file remote execution chain: dist/capture-service-Dx26C5RW.js spawns dist/model-selection-CrrcU32x.js; helper contains network access plus dynamic code execution.
L6: import { l as graphEventOutboxSize } from "./graph-preview-outbox-CyM4KFKo.js";
L7: import { g as pushCaptureEvent, h as onPrivateModeChange, l as drainEvents, m as isPrivateMode, n as resolveVoiceIdentity, p as isAudioMuted, u as flushToDisk, y as sweepTmpDbOrpha...
L8: import { r as resolveCapturePolicy, t as captureSourceEnabled } from "./capture-policy-D_xryvV6.js";
...
L14: import { readdir, rm } from "node:fs/promises";
L15: import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
L16:
...
L77: windowsHide: true
L78: }, (err, stdout) => {
L79: if (err) {
...
L122: async function capture
Findings
6 Critical26 High9 Medium6 Low
CriticalHardcoded Runtime Data Exfiltrationdist/browser-view-proxy-CtFk0vTA.js
77import { a as formatTokenCount$2, i as estimateUsageCost, o as formatUsd$1, s as resolveModelCostConfig } from "./transcript-tools-Dh6Aqffi.js";
L78: import { a as minSecurity, d as resolveExecApprovalsFromFile, i as maxAsk, l as resolveSafeBins, o as recordAllowlistUse, r as evaluateShellAllowlist, s as requiresExecApproval, t ...
L79: import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as buildNodeShellCommand, i as parseEnvPairs, l as parseCameraSnapPayload, n as screenRecordTempPath, o as pars...
L80: import { a as browserSnapshot, c as browserStop, d as fetchBrowserJson, i as browserProfiles, l as browserTabs, n as browserFocusTab, o as browserStart, r as browserOpenTab, s as b...
...
L114: import { createInterface } from "node:readline";
L115: import { createSer
Critical
Credential Exfiltration
Source appears to send environment or credential material to an external endpoint.
77Trigger-reachable credential exfiltration chain: manifest.main -> dist/index.js -> dist/reply-FIdUef8u.js
L77: import { a as formatTokenCount$2, i as estimateUsageCost, o as formatUsd$1, s as resolveModelCostConfig } from "./transcript-tools-Dh6Aqffi.js";
L78: import { a as minSecurity, d as resolveExecApprovalsFromFile, i as maxAsk, l as resolveSafeBins, o as recordAllowlistUse, r as evaluateShellAllowlist, s as requiresExecApproval, t ...
L79: import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as buildNodeShellCommand, i as parseEnvPairs, l as parseCameraSnapPayload, n as screenRecordTempPath, o as pars...
L80: import { a as browserSnapshot, c as browserStop, d as fetchBrowserJson, i as browserProfiles, l as browserTabs, n as browserFocusTab, o as browserStart, r as bro
High
Trigger Reachable Credential Exfiltration
A manifest entrypoint or package-local install chain reaches credential exfiltration behavior.
•Manifest-reachable source captures an API credential, sends it to a fixed unofficial gateway, and persists that redirection in agent or shell configuration.
dist/dist-BCj6Lpia.js:
import { accessSync, constants, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
import { appendFileSync as appendFileSync$1, chmodSync as chmodSync$1, closeSync as closeSync$1, constants as constants$1, createWriteStream as createWriteStream$1, existsSync as e...
import { access as access$1, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$2, stat as stat$1, writeFile as writeFile$1 } from "fs/promises";
import { createInterface } from "node:readline";
import * as readline$1 from "readline";
import { createInterface as createInterf
High
Credential Redirect Persistence
Manifest-reachable source sends a prompted API credential to a fixed unofficial gateway and persists the redirection.
74import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8_fOi.js";
L115: import { _ as setAudioMuted, m as isPrivateMode, p as isAudioMuted, v as setPrivateMode } from "./identify-C0F6NK6E.js";
L1
Critical
Remote Asset Decode Execute
Source fetches a remote non-code asset, decodes its contents, and dynamically executes the decoded payload.
74import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8_fOi.js";
L115: import { _ as setAudioMuted, m as isPrivateMode, p as isAudioMuted, v as setPrivateMode } from "./identify-C0F6NK6E.js";
L1
High
Command Output Exfiltration
Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.
74Detached bundled service listener: dist/gateway-cli-DMSk-W2B.js spawns dist/reply-FIdUef8u.js; helper exposes a broad-bound HTTP listener.
L74: import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8
High
Spawned Bundled Service Listener
Source launches a detached bundled service that exposes a broad-bound HTTP listener.
48import fs$1 from "node:fs/promises";
L49: import { execFile, spawn, spawnSync } from "node:child_process";
L50: import { Writable } from "node:stream";
...
L77: if (resolved === path.parse(resolved).root) return true;
L78: const home = resolveHomeDir();
L79: if (home && resolved === path.resolve(home)) return true;
...
L136: * historically left behind — so an uninstall wasn't "no trace":
L137: * - the private Node runtime (~/.skykoi-node) it drops when no system Node,
L138: * - the `koi` shims in the npm prefix (incl. a hand-written dev shim that
...
L154: });
L155: if (process.platform === "win32") {
L156: const prefix = path.join(process.env.APPDATA || path.join(home, "AppData", "Roaming"), "npm");
High
Obfuscated Payload Loader
Source contains an obfuscated payload loader that reconstructs and executes hidden code.
•Remote response is passed to a worker and executed with Node capabilities.
dist/login-qr-DVznA1do.js:
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D_gEzPfs.js";
var require_eventemitter3 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_aspromise = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_base64 = /* @__PURE__ */ __commonJSMin(((exports) => {
var require_eventemitter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_float = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_inquire$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
* Requires a module only if available.
dist/reply-FIdUef8u.js:
import { i as __require, o as __toESM, r as __exportAll, t as __commo
Critical
Remote Response Code Execution
Source passes code obtained from a remote response into a dynamic execution sink.
81 process.stdout.write(`${yellow}! SkyKoi: v${latest} failed its health check on this machine earlier - staying on v${VERSION}. Retry with: skykoi update --retry-blocked${reset}\n`);
82return;
83 }
84 process.stdout.write(`${cyan}* SkyKoi: new version v${latest} available - updating now (you're on v${VERSION})...${reset}\n`);
77import { a as formatTokenCount$2, i as estimateUsageCost, o as formatUsd$1, s as resolveModelCostConfig } from "./transcript-tools-Dh6Aqffi.js";
L78: import { a as minSecurity, d as resolveExecApprovalsFromFile, i as maxAsk, l as resolveSafeBins, o as recordAllowlistUse, r as evaluateShellAllowlist, s as requiresExecApproval, t ...
L79: import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as buildNodeShellCommand, i as parseEnvPairs, l as parseCameraSnapPayload, n as screenRecordTempPath, o as pars...
L80: import { a as browserSnapshot, c as browserStop, d as fetchBrowserJson, i as browserProfiles, l as browserTabs, n as browserFocusTab, o as browserStart, r as browserOpenTab, s as b...
...
L114: import { createInterface } from "node:readline";
L115: import { createSer
Critical
Credential Exfiltration
Source appears to send environment or credential material to an external endpoint.
77Trigger-reachable credential exfiltration chain: manifest.main -> dist/index.js -> dist/reply-FIdUef8u.js
L77: import { a as formatTokenCount$2, i as estimateUsageCost, o as formatUsd$1, s as resolveModelCostConfig } from "./transcript-tools-Dh6Aqffi.js";
L78: import { a as minSecurity, d as resolveExecApprovalsFromFile, i as maxAsk, l as resolveSafeBins, o as recordAllowlistUse, r as evaluateShellAllowlist, s as requiresExecApproval, t ...
L79: import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as buildNodeShellCommand, i as parseEnvPairs, l as parseCameraSnapPayload, n as screenRecordTempPath, o as pars...
L80: import { a as browserSnapshot, c as browserStop, d as fetchBrowserJson, i as browserProfiles, l as browserTabs, n as browserFocusTab, o as browserStart, r as bro
High
Trigger Reachable Credential Exfiltration
A manifest entrypoint or package-local install chain reaches credential exfiltration behavior.
74import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8_fOi.js";
L115: import { _ as setAudioMuted, m as isPrivateMode, p as isAudioMuted, v as setPrivateMode } from "./identify-C0F6NK6E.js";
L1
Critical
Remote Asset Decode Execute
Source fetches a remote non-code asset, decodes its contents, and dynamically executes the decoded payload.
74import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8_fOi.js";
L115: import { _ as setAudioMuted, m as isPrivateMode, p as isAudioMuted, v as setPrivateMode } from "./identify-C0F6NK6E.js";
L1
High
Command Output Exfiltration
Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.
48import fs$1 from "node:fs/promises";
L49: import { execFile, spawn, spawnSync } from "node:child_process";
L50: import { Writable } from "node:stream";
...
L77: if (resolved === path.parse(resolved).root) return true;
L78: const home = resolveHomeDir();
L79: if (home && resolved === path.resolve(home)) return true;
...
L136: * historically left behind — so an uninstall wasn't "no trace":
L137: * - the private Node runtime (~/.skykoi-node) it drops when no system Node,
L138: * - the `koi` shims in the npm prefix (incl. a hand-written dev shim that
...
L154: });
L155: if (process.platform === "win32") {
L156: const prefix = path.join(process.env.APPDATA || path.join(home, "AppData", "Roaming"), "npm");
High
Obfuscated Payload Loader
Source contains an obfuscated payload loader that reconstructs and executes hidden code.
•Remote response is passed to a worker and executed with Node capabilities.
dist/login-qr-DVznA1do.js:
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D_gEzPfs.js";
var require_eventemitter3 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_aspromise = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_base64 = /* @__PURE__ */ __commonJSMin(((exports) => {
var require_eventemitter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_float = /* @__PURE__ */ __commonJSMin(((exports, module) => {
var require_inquire$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
* Requires a module only if available.
dist/reply-FIdUef8u.js:
import { i as __require, o as __toESM, r as __exportAll, t as __commo
Critical
Remote Response Code Execution
Source passes code obtained from a remote response into a dynamic execution sink.
6Cross-file remote execution chain: dist/capture-service-Dx26C5RW.js spawns dist/model-selection-CrrcU32x.js; helper contains network access plus dynamic code execution.
L6: import { l as graphEventOutboxSize } from "./graph-preview-outbox-CyM4KFKo.js";
L7: import { g as pushCaptureEvent, h as onPrivateModeChange, l as drainEvents, m as isPrivateMode, n as resolveVoiceIdentity, p as isAudioMuted, u as flushToDisk, y as sweepTmpDbOrpha...
L8: import { r as resolveCapturePolicy, t as captureSourceEnabled } from "./capture-policy-D_xryvV6.js";
...
L14: import { readdir, rm } from "node:fs/promises";
L15: import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
L16:
...
L77: windowsHide: true
L78: }, (err, stdout) => {
L79: if (err) {
...
L122: async function capture
High
Cross File Remote Execution Context
Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.
22constr= (t) =>newUint8Array(t.length/2).map(((n, e) =>parseInt(t.substring(2* e, 2* (e +1)), 16))), o= (t) =>r(t)[0], s=/* @__PURE__ */newMap();
23 [
24 ,
258364,
26 ,
278218,
28402,
298222,
308230,
318224,
328225,
33710,
348240,
35352,
368249,
37338,
"./session-key-Fj4XBCFi.js"
;
4import { b as sleep, h as resolveUserPath } from"./utils-BAOd8Jgt.js";
5import { S as ensureKoiWorkspace, b as DEFAULT_TOOLS_FILENAME, f as DEFAULT_BOOTSTRAP_FILENAME, g as DEFAULT_KOI_WORKSPACE_DIR, h as DEFAULT_KOIS_FILENAME, i as resolveKoiConfig, m as DEFAULT_IDENTITY_FILENAME, p as DEFAULT_HEARTBEAT_FILENAME, u as resolveSessionKoiId, x as DEFAULT_USER_FILENAME, y as DEFAULT_SOUL_FILENAME } from"./koi-scope-iDCatsHs.js";
6import { St as loadConfig } from"./model-selection-CrrcU32x.js";
7import { t as formatCliCommand } from"./command-format-CUNsIuO_.js";
8import { A as resolveKoiMainSessionKey, O as canonicalizeMainSessionAlias } from"./sessions-CwFMWY15.js";
9import { a as expandToolGroups } from"./tool-policy-wBzoa3Ny.js";
10import { a as DEFAULT_BROWSER_EVALUATE_ENABLED, c as DEFAULT_SKYKOI_BROWSER_PROFILE_NAME, o as DEFAULT_SKYKOI_BROWSER_COLOR } from"./constants-DQkPPQQ3.js";
11import { o as syncSkillsToWorkspace } from"./skills-CxxUdFw-.js";
12import { t as registerBrowserRoutes } from"./routes-BYqPqHjs.js";
13import { a as resolveProfile } from"./config-CIm-DOfd.js";
14import { t as createBrowserRouteContext } from"./server-context-o-VOmJrC.js";
•Manifest-reachable source captures an API credential, sends it to a fixed unofficial gateway, and persists that redirection in agent or shell configuration.
dist/dist-BCj6Lpia.js:
import { accessSync, constants, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
import { appendFileSync as appendFileSync$1, chmodSync as chmodSync$1, closeSync as closeSync$1, constants as constants$1, createWriteStream as createWriteStream$1, existsSync as e...
import { access as access$1, mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$2, stat as stat$1, writeFile as writeFile$1 } from "fs/promises";
import { createInterface } from "node:readline";
import * as readline$1 from "readline";
import { createInterface as createInterf
High
Credential Redirect Persistence
Manifest-reachable source sends a prompted API credential to a fixed unofficial gateway and persists the redirection.
74Detached bundled service listener: dist/gateway-cli-DMSk-W2B.js spawns dist/reply-FIdUef8u.js; helper exposes a broad-bound HTTP listener.
L74: import { a as resolveOutboundTarget, o as resolveSessionDeliveryTarget, u as normalizePollInput } from "./message-DWTRR9ll.js";
L75: import { i as [redacted], s as verifyDeviceSignature, t as deriveDeviceIdFromPublicKey } from "./device-identity-B7IOnQqh.js";
L76: import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Dcbe4Oxv.js";
L77: import { $ as validateNodePairListParams, A as [redacted], At as ErrorCodes, B as validateKoiIdentityParams, C as validateCronUpdateParams, Ct as validateWeb...
L78: import { n as callGateway, s as loadGatewayTlsRuntime$1 } from "./call-DSDuysej.js";
...
L114: import "./graph-access-Dtz8
High
Spawned Bundled Service Listener
Source launches a detached bundled service that exposes a broad-bound HTTP listener.