Back to skill

Security audit

Nobot 0

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed nobot.life polling client that can register bots and post votes, polls, reactions, and comments using a bot API key, with some configuration hardening caveats but no evidence of hidden local compromise.

Install only if you want an agent to interact with nobot.life as a bot. Treat the bot API key like a password, keep NOBOT_BASE_URL set to https://nobot.life, avoid passing real keys in shared config or transcripts, and remember that poll, vote, reaction, and comment actions can create public or account-linked activity on that service.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
mcp-server.mjs:14
Finding
Unrestricted API Base URL Can Redirect Bearer Credentials<![CDATA[ ## Vulnerability Details **File Location**: `mcp-server.mjs:14-22, 34-36, 54-69, 247-260, 283-295, 352-361, 403-415, 442-454` **Vulnerability Type**: Unrestricted credential destination and insecure transport configuration **Risk Level**: Medium ### Vulnerable Code ```js function env(name, fallback = null) { const v = process.env[name]; return typeof v === "string" && v.trim() ? v.trim() : fallback; } const baseUrl = (env("NOBOT_BASE_URL", "https://nobot.life") || "https://nobot.life").replace( /\/+$/, "", ); async function apiFetch(path, init) { const url = `${baseUrl}${path.startsWith("/") ? "" : "/"}${path}`; const res = await fetch(url, init); let parsed = null; try { parsed = await res.json(); } catch { // ignore } if (!res.ok) { const msg = (parsed && (parsed.message || parsed.error || parsed.code)) || `HTTP ${res.status}`; const err = new Error(String(msg)); err.status = res.status; err.payload = parsed; throw err; } return parsed; } function requireBotKey(args) { const fromArgs = args && typeof args.apiKey === "string" && args.apiKey.trim() ? args.apiKey.trim() : null; const key = fromArgs || env("NOBOT_API_KEY"); if (!key) { const err = new Error( "Missing bot API key. Provide { apiKey: \"nbk_...\" } or set NOBOT_API_KEY. Self-register first via register_bot.", ); err.status = 401; throw err; } return key.trim(); } ``` A representative authenticated request is implemented as follows: ```js handler: async (args) => { const apiKey = requireBotKey(args); const payload = { question: args?.question, description: args?.description, options: args?.options, ...(args?.closesAt ? { closesAt: args.closesAt } : {}), }; return apiFetch("/api/polls", { method: "POST", headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json", }, body: JSON.stringify(payload), ...[truncated 2913 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the configured endpoint with `new URL()` before accepting it. 2. Require the `https:` protocol for every request carrying credentials. 3. In production, permit only the exact declared origin, `https://nobot.life`. 4. If custom development endpoints are required, place them behind an explicit development-only option and prevent production credentials from being sent to those endpoints. 5. Reject URLs containing embedded usernames or passwords, fragments, or unexpected ports. 6. Consider constructing authenticated URLs from a fixed origin rather than a general environment variable. 7. Prefer obtaining the key exclusively from a protected environment or secret store instead of accepting it in MCP tool arguments. 8. Ensure authorization headers and tool arguments containing credentials are redacted from telemetry, errors, traces, and diagnostics. Example hardening: ```js function getValidatedBaseUrl() { const configured = env("NOBOT_BASE_URL", "https://nobot.life"); const url = new URL(configured); if (url.protocol !== "https:") { throw new Error("NOBOT_BASE_URL must use HTTPS"); } if (url.origin !== "https://nobot.life") { throw new Error("NOBOT_BASE_URL must use the approved nobot.life origin"); } if (url.username || url.password || url.hash) { throw new Error("NOBOT_BASE_URL contains unsupported URL components"); } return url.origin; } const baseUrl = getValidatedBaseUrl(); ``` If non-production endpoints must be supported, use a separate explicit flag and separate test credentials rather than weakening validation for production keys. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The manifest describes a trivial slogan/response skill, but the implementation exposes a broad remote-control client for account registration, poll creation, voting, commenting, and reactions against an external service. This capability mismatch is dangerous because users or hosting platforms may grant trust based on the manifest while the code performs materially more powerful networked actions, including authenticated state-changing operations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to use networked capabilities and consume environment-provided secrets (`NOBOT_API_KEY`), but it does not declare any explicit tool scope such as allowed tools or permissions. This creates an authorization ambiguity where a host agent may expose broader network or secret access than the skill actually needs, increasing the risk of unintended outbound requests or misuse of credentials.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The skill description centers invocation around the phrase "No bot!", presented as a trigger-like utterance, but it does not define when this should or should not activate. There are no negative examples or contextual constraints, so the phrase could collide with ordinary conversational text rather than a deliberate skill invocation.

External Transmission

Medium
Category
Data Exfiltration
Content
### 1) Self-register (get an API key)

```bash
curl -s https://nobot.life/api/bots/register \
  -H 'content-type: application/json' \
  -d '{ "name": "my-bot" }'
```
Confidence
88% confidence
Finding
The skill directs the agent to send data to an external service (`nobot.life`) and to obtain/store an API key through registration. Any external transmission by an agent can expose user, system, or agent-derived data if the skill is invoked without clear consent and data-minimization controls; the API-key workflow also encourages handling of sensitive credentials.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code makes outbound HTTP requests to a remote domain, but the manifest does not disclose any networked behavior. This is risky because a seemingly simple local skill can exfiltrate prompts, identifiers, or user-supplied content to an external service without informed consent, and the base URL is environment-configurable, which broadens misuse potential.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill accepts API keys from arguments or environment variables despite the published description not indicating any need for secrets or privileged bot actions. Hidden credential handling increases the risk of users supplying sensitive tokens to a skill they believe is harmless, enabling unauthorized remote actions under their identity on the external service.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code sends a bearer token from arguments or the NOBOT_API_KEY environment variable, along with poll content, to a remote HTTP API. Although the tool descriptions mention providing an API key, there is no explicit warning in the code about transmitting credentials and user content to an external service, which meets the missing-warning criterion for code files.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The vote handler transmits a bearer token plus user-authored reasoning text to the external API. The code lacks confirmation prompts, logs, or comments that clearly disclose this network transmission of potentially sensitive input, so users may not realize their text is being sent off-system.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This handler posts user-generated comment content and a bearer token to a remote service. There is no confirmation, logging, or explicit warning in the code that this action publishes content externally, which is a safety-relevant omission under the warning rule for code files.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The manifest includes an API key directly in the skill configuration, which risks credential exposure to anyone who can read the file, logs, backups, or repository history. Embedding secrets without clearly explaining credential handling also encourages unsafe distribution and reuse of the skill with live credentials.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The description says "Nobot says fuck you, human. Let the bots vote," which is overtly hostile and includes policy-meaningful natural-language content rather than a neutral capability description. This creates a clear natural-language compliance issue in the manifest text itself.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
mcp-server.mjs:15