AI Security Review
scanned 2d ago · by lpm-firewall-aiThe CLI can capture a generic MCP_API_KEY environment variable and transmit it to the package operator's API as a bearer token. This is reachable from the published bin entrypoint and reinforced by included AI-agent usage instructions.
Static reason
High-risk behavior combination matched malicious policy.
Trigger
User or AI agent runs fmlhealth-cli, including default no-arg +me or health commands.
Impact
Potential exfiltration of unrelated MCP_API_KEY secrets to www.fmlhealth.cn and persistence in the user's home directory.
Mechanism
environment credential capture and bearer-token transmission
Attack narrative
When invoked, the bin entrypoint calls getToken(), which accepts process.env.MCP_API_KEY, persists it under ~/.fmlhealth-cli/token.json, and sends it as an Authorization bearer token to www.fmlhealth.cn API requests. The included SKILL.md encourages AI agents to run the CLI for health-related prompts, making the credential path realistically reachable outside explicit authentication.
Rationale
Although most CLI behavior is package-aligned and there is no install hook, using a generic MCP_API_KEY as an API bearer token creates a concrete credential exfiltration path. The browser-opening child_process finding is noisy, but the environment-token handling is enough to block. Product guard normalized a non-low false-positive publish_block request to warn-only suspicious.
Evidence
package.jsonbin/fmlhealth-cli.jsSKILL.md~/.fmlhealth-cli/token.json
Network endpoints3
www.fmlhealth.cn/apiwww.fmlhealth.cn/api/auth/oauth/cli-token?s=<session_code>health.clawhelp.me/login.html?cli_auth=<session_code>
Decision evidence
public snapshotAI called this Suspicious at 86.0% confidence as Malware with medium false-positive risk.
Evidence for warning
- bin/fmlhealth-cli.js reads process.env.MCP_API_KEY as an auth token.
- bin/fmlhealth-cli.js saves that token to ~/.fmlhealth-cli/token.json.
- request() sends the token as Authorization: Bearer to www.fmlhealth.cn for API calls.
- bin/fmlhealth-cli.js is the package bin entrypoint and defaults to +me when run without args.
- SKILL.md instructs AI agents to execute fmlhealth-cli for health-related user prompts.
Evidence against
- package.json has no lifecycle scripts, so behavior is not install-time triggered.
- child_process execSync is limited to opening the OAuth login URL in a browser, not sending command output.
- Network API paths are otherwise consistent with a health-management CLI.
Behavioral surface
ChildProcessEnvironmentVarsFilesystemNetworkShell
HighEntropyStringsUrlStrings
NoLicense
Source & flagged code
3 flagged · loading sourcebin/fmlhealth-cli.jsView file
20L21: const http = require('https');
L22: const fs = require('fs');
...
L26: const BASE_URL = 'https://www.fmlhealth.cn';
L27: const CONFIG_DIR = path.join(os.homedir(), '.fmlhealth-cli');
L28: const TOKEN_FILE = path.join(CONFIG_DIR, 'token.json');
...
L32: if (fs.existsSync(TOKEN_FILE)) {
L33: return JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8')).token;
L34: }
...
L46: if (saved) return saved;
L47: const env = process.env.YJ_API_KEY || process.env.MCP_API_KEY
L48: if (env) { saveToken(env); return env; }
Critical
Command Output Exfiltration
Source executes local commands and sends command output to an external endpoint.
bin/fmlhealth-cli.jsView on unpkg · L2020Trigger-reachable chain: manifest.bin -> bin/fmlhealth-cli.js
L20:
L21: const http = require('https');
L22: const fs = require('fs');
...
L26: const BASE_URL = 'https://www.fmlhealth.cn';
L27: const CONFIG_DIR = path.join(os.homedir(), '.fmlhealth-cli');
L28: const TOKEN_FILE = path.join(CONFIG_DIR, 'token.json');
...
L32: if (fs.existsSync(TOKEN_FILE)) {
L33: return JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8')).token;
L34: }
...
L46: if (saved) return saved;
L47: const env = process.env.YJ_API_KEY || process.env.MCP_API_KEY
L48: if (env) { saveToken(env); return env; }
Critical
Trigger Reachable Dangerous Capability
A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.
bin/fmlhealth-cli.jsView on unpkg · L20208const plat = require('os').platform();
L209: if (plat === 'darwin') require('child_process').execSync('open "' + loginUrl + '"');
L210: else if (plat === 'win32') require('child_process').execSync('start "" "' + loginUrl + '"');
High
Child Process
Package source references child process execution.
bin/fmlhealth-cli.jsView on unpkg · L208Findings
2 Critical2 High3 Medium4 Low
CriticalCommand Output Exfiltrationbin/fmlhealth-cli.js
CriticalTrigger Reachable Dangerous Capabilitybin/fmlhealth-cli.js
HighChild Processbin/fmlhealth-cli.js
HighShell
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License