T09 · Insecure Skill Coding Practices
- Location
scripts/run.js:48- Finding
Arbitrary MCP Endpoint Override Can Disclose the API Token
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Twitter/X analytics skill is not clearly malicious, but its bundled runner is broader than the Twitter-only description and handles the API token in ways users should review.
Install only if you are comfortable giving the skill a KeyAPI token and storing Twitter/X query results locally. Prefer setting KEYAPI_TOKEN in your shell instead of entering it at the prompt, avoid KEYAPI_SERVER_URL unless you trust the endpoint, and delete or protect any .env file created in the skill directory.
scripts/run.js:48Arbitrary MCP Endpoint Override Can Disclose the API Token
scripts/run.js:240API Token Is Persisted in a Plaintext File Without Explicit Restrictive Permissions
The static finding indicates the skill can drive a generic multi-platform MCP runner and invoke arbitrary available server tools, while the description presents it as Twitter/X-specific analytics. That mismatch is dangerous because users and policy systems may grant trust or access based on the declared purpose, while the actual capability surface is broader and may include unrelated platforms, filesystem writes, and token handling not disclosed in the description.
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Referenced artifact was not completely inspected
node scripts/run.js --platform twitter --list-tools
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, "..");
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, "..");
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, "..");
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, "..");
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
if (!existsSync(envPath)) return;
for (const line of readFileSync(envPath, "utf8").split("\n")) {
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
// ── .env loader ───────────────────────────────────────────────────────────────
(function loadDotenv() {
const envPath = join(ROOT, ".env");
if (!existsSync(envPath)) return;
for (const line of readFileSync(envPath, "utf8").split("\n")) {
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);
No suspicious patterns detected.