Back to skill

Security audit

Janee

Security checks for vulnerabilities and agentic risk

Overview

Janee is a disclosed API-credential proxy, but a verified URL-handling flaw could let an agent send stored credentials to an attacker-controlled URL.

Review before installing, especially with production or high-privilege API keys. Do not rely on the current package to prevent key exfiltration from a compromised or prompt-injected agent until it rejects absolute/protocol-relative paths, validates the final request origin before adding credentials, requires HTTPS except explicit local development, encrypts all credential-bearing fields, and updates flagged dependencies.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
src/cli/commands/serve-mcp.ts:76
Finding
Agent-Controlled Absolute URL Can Exfiltrate Stored API Credentials## Vulnerability Details **File Location**: `src/cli/commands/serve-mcp.ts:76-115`; policy handling occurs at `src/core/mcp-server.ts:219-263` **Vulnerability Type**: Origin validation failure and credential disclosure **Risk Level**: High ### Vulnerable Code ```ts // Build target URL (properly join base + path) let baseUrl = serviceConfig.baseUrl; if (!baseUrl.endsWith('/')) baseUrl += '/'; let reqPath = request.path; if (reqPath.startsWith('/')) reqPath = reqPath.slice(1); const targetUrl = new URL(reqPath, baseUrl); // Build headers const headers: Record<string, string> = { ...request.headers }; // Inject auth if (serviceConfig.auth.type === 'bearer' && serviceConfig.auth.key) { headers['Authorization'] = `Bearer ${serviceConfig.auth.key}`; } else if (serviceConfig.auth.type === 'headers' && serviceConfig.auth.headers) { Object.assign(headers, serviceConfig.auth.headers); } else if (serviceConfig.auth.type === 'hmac' && serviceConfig.auth.apiKey && serviceConfig.auth.apiSecret) { // HMAC signature (MEXC-style) const timestamp = Date.now().toString(); targetUrl.searchParams.set('timestamp', timestamp); // Create signature from query string const queryString = targetUrl.searchParams.toString(); const signature = createHmac('sha256', serviceConfig.auth.apiSecret) .update(queryString) .digest('hex'); targetUrl.searchParams.set('signature', signature); headers['X-MEXC-APIKEY'] = serviceConfig.auth.apiKey; } // Set Content-Type for requests with body if (request.body && !headers['Content-Type'] && !headers['content-type']) { headers['Content-Type'] = 'application/json'; } // Make API request const response = await makeAPIRequest(targetUrl, { ...request, headers }); ``` ### Technical Analysis The MCP caller controls `request.path`. The implementation removes one leading slash and passes ...[truncated 1937 chars]
Remediation
## Remediation Suggestions 1. Require request paths to be relative API paths beginning with exactly one `/`. 2. Reject absolute URLs, protocol-relative values such as `//attacker.example`, embedded credentials, backslashes, and control characters. 3. Resolve the path before adding credentials, then compare the resolved URL against the configured base URL: - Protocol must match. - Hostname must match. - Effective port must match. - Username and password must be empty. 4. Inject credentials only after successful origin validation. 5. Prefer constructing the outbound URL by assigning a validated pathname and query to a copy of the configured base URL instead of resolving arbitrary input. 6. Keep redirects disabled, or independently validate every redirect destination before forwarding credentials. 7. Add regression tests for absolute URLs, protocol-relative URLs, HTTP downgrade attempts, encoded separators, backslashes, embedded credentials, and cross-origin redirects. 8. Consider making policy matching operate on a canonicalized pathname and query only.

T09 · Insecure Skill Coding Practices

Warning
Location
src/cli/config-yaml.ts:91
Finding
Credential Protection Is Incomplete at Rest and in Transit## Vulnerability Details **File Location**: `src/cli/config-yaml.ts:91-147`, `src/cli/config-yaml.ts:153-170`, and `src/cli/commands/add.ts:40-49` **Vulnerability Type**: Ineffective key separation, plaintext credential storage, and cleartext credential transport **Risk Level**: Medium ### Vulnerable Code The encryption key is part of the same configuration object that contains encrypted credentials: ```ts const config: JaneeYAMLConfig = { version: '0.2.0', masterKey: generateMasterKey(), server: { port: 9119, host: 'localhost' }, services: {}, capabilities: {} }; saveYAMLConfig(config); ``` Saving encrypts bearer and HMAC values, but does not encrypt credential-bearing custom headers: ```ts export function saveYAMLConfig(config: JaneeYAMLConfig): void { // Encrypt service auth keys before saving const configCopy = JSON.parse(JSON.stringify(config)); for (const [name, service] of Object.entries(configCopy.services)) { const svc = service as ServiceConfig; if (svc.auth.type === 'bearer' && svc.auth.key) { svc.auth.key = encryptSecret(svc.auth.key, config.masterKey); } else if (svc.auth.type === 'hmac') { if (svc.auth.apiKey) { svc.auth.apiKey = encryptSecret(svc.auth.apiKey, config.masterKey); } if (svc.auth.apiSecret) { svc.auth.apiSecret = encryptSecret(svc.auth.apiSecret, config.masterKey); } } } const yamlContent = yaml.dump(configCopy, { indent: 2, lineWidth: 120 }); fs.writeFileSync(CONFIG_FILE_YAML, yamlContent, { mode: 0o600 }); } ``` The service URL validation also accepts cleartext HTTP: ```ts let baseUrl = options.url; if (!baseUrl) { baseUrl = await rl.question('Base URL: '); baseUrl = baseUrl.trim(); } if (!baseUrl || !baseUrl.startsWith('http')) { console.error('❌ Invalid base URL. Must start with http:// or https://'); ...[truncated 2610 chars]
Remediation
## Remediation Suggestions 1. Store the master key separately from `config.yaml`, preferably in the operating system credential manager, platform keychain, TPM-backed storage, or a user-supplied secret source. 2. If a keychain is unavailable, support a passphrase-derived key using a memory-hard KDF such as Argon2id or scrypt with a unique salt and appropriate parameters. 3. Encrypt every credential-bearing value, including all values under `auth.headers`. 4. Introduce an explicit encrypted-value format marker rather than treating every decryption failure as evidence that a value is plaintext. 5. Require `https:` for remote service URLs. 6. If HTTP is necessary for local development, permit it only through an explicit opt-in restricted to loopback addresses or trusted Unix-domain alternatives. 7. Validate URLs with the `URL` parser rather than using `startsWith('http')`; reject unsupported schemes, embedded credentials, and malformed hosts. 8. Update security documentation to explain the actual threat model and avoid implying that same-file encryption protects credentials after complete configuration-file disclosure. 9. Preserve restrictive file and directory permissions and verify permissions when loading existing files.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (75)

Known Vulnerable Dependency: vitest==3.2.4 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: vitest==3.2.4 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding
vitest 3.2.4 is flagged with critical advisories for arbitrary file read and execution/path traversal, but it is present only as a devDependency. This reduces direct production exposure, though it still poses risk in developer environments or CI if the Vitest UI/server is used, where repository secrets or local files could be accessed.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- `GET *` → any GET request
- `POST /v1/charges/*` → POST to /v1/charges/ and subpaths
- `* /v1/customers` → any method to /v1/customers
- `DELETE /v1/customers/*` → DELETE any customer

**This makes security real:** Even if an agent lies about its "reason", it can only access the endpoints the policy allows. Enforcement happens server-side.
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description emphasizes secrets management and preventing API key exposure. The supplied code chunk does not manage, store, rotate, redact, or protect secrets. Instead, it checks for a local YAML config, loads it, and lists configured services and capabilities to the console, including service URLs and auth types. That is a configuration-inspection/listing function, not a secrets-management function. While this may be part of a broader tool, this specific code's primary purpose is materially different from the declared description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose is secrets management and protection of API keys, but the supplied code chunk does not manage, store, redact, rotate, or protect secrets. Instead, it is a logging/audit viewer for recent or live proxy activity. This is a materially different primary purpose and introduces undeclared capabilities around log access and monitoring. Therefore the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The description suggests a secrets-management tool whose primary role is to securely store or mediate access to API keys so they are never exposed. The code instead implements a serving command for an MCP server that proxies requests to configured external services, dynamically injects credentials into outgoing requests, supports bearer/header/HMAC auth, logs activity, and manages sessions. While it uses secrets as part of request authentication, it is not primarily a secrets manager in the usual sense (e.g., storing, rotating, vaulting, or access-controlling secrets). Its main behavior is an API execution/proxy server, which is a materially different and broader capability than declared.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose centers on secrets management for AI agents, but the supplied code chunk implements a serve command that launches an MCP server. Based on this snippet, the primary behavior is server startup, which is materially different from secret management. There is no evidence here of managing API keys or preventing exposure of secrets. Therefore the description does not accurately represent the behavior shown.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared purpose emphasizes secrets management and protecting API keys, but this code does not manage, store, redact, rotate, or protect secrets. Instead, it lists active sessions from a local sessions file and displays session metadata in the terminal. That is a materially different primary purpose: session inspection rather than secrets management. While sessions may be related to access control, the behavior shown here is not accurately represented by the description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description says this skill provides secrets management and protects API keys, but the supplied code does not manage, store, retrieve, encrypt, rotate, or redact secrets. Instead, it creates local audit logs for API activity, writes events to daily JSONL files, reads them back with filters, and streams new log entries. This is a materially different primary purpose and introduces undeclared file-system logging and log-reading capabilities. Therefore, the description does not accurately represent the code's actual behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says the skill is for secrets management and protecting API keys. However, the supplied code chunk does not implement secrets storage, redaction, secure retrieval, or key protection behavior. It is only a test suite for MCP server initialization and reload_config behavior. Although mock service configs include bearer keys as test data, the code does not actually manage secrets. The primary purpose of the code is materially different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose claims secrets management and protection of API keys, but the supplied code chunk contains only tests for a rules engine. It verifies behavior for allow/deny access rules, wildcard path matching, and rule validation. There is no evidence of secret storage, key masking, credential retrieval, encryption, or any other secrets-management functionality. This is a clear material mismatch in primary purpose and capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description emphasizes secrets management and protecting API keys, but the supplied code does not manage, store, mask, retrieve, or protect secrets. Instead, it enforces request access policies based on HTTP method/path rules and validates those rule definitions. This is a materially different primary purpose, so the description does not accurately represent the code's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description says the skill is for secrets management and protecting API keys, but the code shown does not manage secrets at all. It defines a SessionManager that tracks capability sessions with IDs, service/capability metadata, creation and expiration times, revocation state, and persists those sessions to ~/.janee/sessions.json. While persistence and token generation could be supporting details, the primary behavior here is session tracking with TTL, not secret vaulting, key protection, or secret retrieval. Therefore the description does not accurately represent the actual code behavior.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Old way (dangerous):
curl -H "Authorization: Bearer sk_live_xxx" https://api.stripe.com/v1/balance

# Janee way (safe):
# Agent calls execute(capability, method, path) via MCP
Confidence
87% confidence
Finding
The documented interface lets an agent call execute(capability, method, path), and without explicit constraints in the skill metadata this creates a tool-parameter abuse risk. If capabilities are broad or misconfigured, an injected or compromised agent could choose dangerous methods and paths and cause unauthorized API actions even without seeing the raw secret.

Credential Access

High
Category
Privilege Escalation
Content
## Example: Secure Moltbook Access

Instead of storing your Moltbook key in `~/.config/moltbook/credentials.json`:

```bash
janee add moltbook -u https://www.moltbook.com/api/v1 -k YOUR_KEY
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Now the agent CANNOT:**
- Charge cards (POST /v1/charges)
- Delete customers (DELETE /v1/customers/*)
- Update anything (PUT /v1/*)

**Even if it provides a plausible reason.**
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Known Vulnerable Dependency: @hono/node-server==1.19.9 — 3 advisory(ies): CVE-2026-39406 (@hono/node-server: Middleware bypass via repeated slashes in serveStatic); GHSA-frvp-7c67-39w9 (Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode); CVE-2026-29087 (@hono/node-server has authorization bypass for protected static paths via encode)

High
Category
Supply Chain
Confidence
96% confidence
Finding
The lockfile pins @hono/node-server 1.19.9, and the reported advisories describe real server-side path traversal and authorization/middleware bypass issues in static file handling. Even though this package is transitive, bundling a vulnerable HTTP server component in a secrets-management skill is risky because any exposed local or remote server surface could be used to read protected files or bypass access controls.

Known Vulnerable Dependency: @modelcontextprotocol/sdk==1.25.3 — 1 advisory(ies): CVE-2026-25536 (@modelcontextprotocol/sdk has cross-client data leak via shared server/transport)

High
Category
Supply Chain
Confidence
98% confidence
Finding
The skill directly depends on @modelcontextprotocol/sdk 1.25.3, which is reported as vulnerable to cross-client data leakage via shared server/transport. For a secrets-management tool, cross-session or cross-client data exposure is especially dangerous because one user's credentials or secret material could be disclosed to another client.

Known Vulnerable Dependency: fast-uri==3.1.0 — 7 advisory(ies): CVE-2026-13676 (fast-uri vulnerable to host confusion via failed IDN canonicalization); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +4 more

High
Category
Supply Chain
Confidence
86% confidence
Finding
fast-uri 3.1.0 is included and carries multiple URI parsing issues including host confusion and potential SSRF-related behavior. In a secrets-management skill, any component that validates or normalizes attacker-controlled URLs incorrectly can be used to bypass allowlists or redirect requests toward internal services that expose sensitive data.

Known Vulnerable Dependency: hono==4.11.7 — 16 advisory(ies): CVE-2026-56762 (Hono missing validation of cookie name on write path in setCookie()); CVE-2026-47676 (Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro); CVE-2026-47675 (Hono: Cookie helper does not sanitize sameSite and priority, allowing Set-Cookie) +13 more

High
Category
Supply Chain
Confidence
91% confidence
Finding
hono 4.11.7 has numerous advisories involving cookie handling, route/path normalization, and related web framework security weaknesses. Because this skill manages secrets, weaknesses in routing, cookie construction, or request handling can increase the chance of unauthorized access, session confusion, or exposure of protected resources.

Known Vulnerable Dependency: js-yaml==4.1.1 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
93% confidence
Finding
js-yaml 4.1.1 is directly depended on and is flagged for multiple CPU exhaustion issues involving merge keys and object map resolution. If this skill accepts YAML configuration, secret manifests, or user-provided inputs, an attacker could trigger denial of service and disrupt secret operations or availability.

Known Vulnerable Dependency: nanoid==3.3.11 — 3 advisory(ies): CVE-2026-67214 (nanoid: non-secure generators can loop indefinitely with negative size); CVE-2026-67213 (nanoid: custom generators can loop indefinitely when size is zero); CVE-2026-73086 (nanoid: Integer Overflow or Wraparound)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: path-to-regexp==8.3.0 — 2 advisory(ies): CVE-2026-4923 (path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w); CVE-2026-4926 (path-to-regexp vulnerable to Denial of Service via sequential optional groups)

High
Category
Supply Chain
Confidence
84% confidence
Finding
path-to-regexp 8.3.0 is associated with regular-expression denial-of-service conditions from crafted route patterns or matching behavior. In an HTTP-exposed agent component, ReDoS can be used to stall request processing and degrade availability, which is meaningful for a secrets-management service even if it does not directly expose data.

Known Vulnerable Dependency: picomatch==4.0.3 — 2 advisory(ies): CVE-2026-33672 (Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Mat); CVE-2026-33671 (Picomatch has a ReDoS vulnerability via extglob quantifiers)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: postcss==8.5.6 — 4 advisory(ies): CVE-2026-45623 (PostCSS: Arbitrary file read and information disclosure via attacker-controlled ); CVE-2026-69153 (PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappi); CVE-2026-41305 (PostCSS has XSS via Unescaped </style> in its CSS Stringify Output) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Static analysis

No suspicious patterns detected.