AI Security Review
scanned 2h ago · by lpm-firewall-aiA chat user can supply an image URL that the Koishi host fetches. The fetched bytes can then be sent to the configured image-generation provider, creating SSRF-mediated data exposure.
Static reason
One or more suspicious static signals were detected.
Trigger
User invokes an image generation or editing command with an HTTP image URL.
Impact
Potential access to reachable internal services and exfiltration of response bytes to a configured provider.
Mechanism
Unrestricted server-side image fetch followed by provider upload.
Rationale
Source inspection found no malicious lifecycle, persistence, credential harvesting, or arbitrary payload execution. However, unrestricted user-controlled image fetching creates a concrete SSRF path whose response is forwarded to external configured AI providers.
Evidence
dist/index.jspackage.json
Network endpoints2
generativelanguage.googleapis.comapi.openai.com/v1
Decision evidence
public snapshotAI called this Suspicious at 86.0% confidence as Critical Vulnerability with medium false-positive risk.
Evidence for warning
- `dist/index.js` downloads caller-provided image URLs through `ctx.http.get` without host restrictions.
- Downloaded URL content is base64-encoded and submitted to configured image-provider requests.
- The request path supports `http` image inputs and the download helper accepts arbitrary non-`internal:` URLs.
Evidence against
- `package.json` has no preinstall, install, or postinstall lifecycle hook.
- `new Function` only implements an ESM fallback for two fixed optional ChatLuna module specifiers.
- Observed API keys are configuration fields used as provider credentials and are redacted in logs.
- Filesystem writes are limited to plugin data under `ctx.baseDir/data/aka-ai-image-generator`.
Behavioral surface
DynamicRequireEvalFilesystem
HighEntropyStringsUrlStrings
Source & flagged code
4 flagged · loading sourcedist/index.jsView file
2415patternName = generic_password
severity = medium
line = 2415
matchedText = return s..."');
Medium
38module.exports = __toCommonJS(index_exports);
L39: var import_node_path = __toESM(require("path"));
L40:
Medium
Dynamic Require
Package source references dynamic require/import behavior.
dist/index.jsView on unpkg · L38441} catch (requireError) {
L442: const dynamicImport = new Function("s", "return import(s)");
L443: return dynamicImport(specifier).catch((importError) => {
Low
Eval
Package source references a known benign dynamic code generation pattern.
dist/index.jsView on unpkg · L441dist/index.mjsView file
2378patternName = generic_password
severity = medium
line = 2378
matchedText = return s..."');
Medium
Findings
3 Medium5 Low
MediumSecret Patterndist/index.js
MediumDynamic Requiredist/index.js
MediumSecret Patterndist/index.mjs
LowScripts Present
LowEvaldist/index.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings