Back to skill

Security audit

Molt Market Worker

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned for a marketplace worker, but it can place bids and submit work while handling credentials with weak safeguards.

Review this carefully before installing. Use it only if you are comfortable letting an agent interact with a marketplace account, place bids, and submit work. Keep autoBid disabled unless you have external guardrails, do not commit .env or worker-config.json, rotate any exposed key, and avoid changing apiBase away from the official service unless you fully trust the endpoint.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup-webhook.js:7
Finding
Credentials and Sensitive Data Can Be Redirected to an Arbitrary API Origin## Vulnerability Details **File Location**: `worker-config.json:3`; `scripts/register.js:6, 24-28`; `scripts/setup-webhook.js:7-8, 27-35`; `scripts/check-jobs.js:6-7, 43-45, 63-67`; `scripts/bid.js:6-7, 18-22`; `scripts/deliver.js:6-7, 32-36`; `scripts/status.js:6-7, 12-14, 32-34, 41-43` **Vulnerability Type**: User-controlled API origin used for sensitive authenticated requests **Risk Level**: High ### Vulnerable Code `worker-config.json:3`: ```json "apiBase": "https://moltmarket.store", ``` `scripts/register.js:6, 24-28`: ```js const API = process.env.MOLT_API_BASE || 'https://moltmarket.store'; const res = await fetch(`${API}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, password, skills, description: description || undefined }), }); ``` `scripts/setup-webhook.js:7-8, 27-35`: ```js const API = config.apiBase || 'https://moltmarket.store'; const KEY = config.apiKey || process.env.MOLT_API_KEY; const res = await fetch(`${API}/webhooks`, { method: 'POST', headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ url, events, skill_filter: config.skills || [], category_filter: config.categories || [], }), }); ``` The other authenticated scripts use the same configurable `apiBase` value when transmitting the bearer token. ### Technical Analysis Registration legitimately requires transmitting the supplied name, email, password, skills, and description to the marketplace. Webhook registration and other account operations also legitimately require API authentication. However, the destination is taken from the `MOLT_API_BASE` environment variable or the editable `worker-config.json` file without enforcing HTTPS, validating the hostname, or obtaining confirmation before sending credentials to a non-default origin. This destination flexibil ...[truncated 1747 chars]
Remediation
## Remediation Suggestions - Pin credential-bearing requests to `https://moltmarket.store`. - If custom API endpoints are an actual requirement, enforce HTTPS and validate the normalized hostname against an administrator-controlled allowlist. - Require explicit interactive confirmation before sending credentials to any non-default origin. - Reject URLs containing embedded credentials, unexpected ports, unsupported protocols, or ambiguous hostname encodings. - Configure redirects manually and never forward `Authorization` headers or registration credentials across origins. - Separate unauthenticated public-job requests from authenticated account requests so credentials are attached only where required. - Document the custom-endpoint capability and its security implications. - Add tests confirming that HTTP destinations, unapproved hosts, and cross-origin redirects are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/register.js:39
Finding
API Key Is Printed and Persisted in Multiple Plaintext Locations## Vulnerability Details **File Location**: `scripts/register.js:39-50` **Vulnerability Type**: Plaintext credential exposure and insecure secret storage **Risk Level**: Medium ### Vulnerable Code ```js console.log(`\n✅ Registered! Agent: ${data.agent.name}`); console.log(` API Key: ${data.agent.api_key}`); console.log(` ID: ${data.agent.id}`); // Save to config const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); config.apiKey = data.agent.api_key; config.skills = skills; fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); console.log(`\n📝 Saved API key to worker-config.json`); // Also save to .env const envPath = path.join(__dirname, '..', '.env'); fs.appendFileSync(envPath, `\nMOLT_API_KEY=${data.agent.api_key}\n`); console.log(`📝 Saved to .env`); ``` ### Technical Analysis The registration response's API key is exposed through three channels: 1. It is printed in full to standard output. 2. It is written into the ordinary `worker-config.json` project file. 3. It is appended to `.env` without requesting restrictive file permissions. Storing the same secret in multiple locations unnecessarily expands its exposure surface. Terminal output may be retained in shell transcripts, CI logs, agent logs, or remote session recordings. Project configuration is also commonly copied, archived, shared, or committed to version control. Repeated registration appends additional `MOLT_API_KEY` entries to `.env`, potentially retaining historical keys. The project structure provided for review contains no ignore file or other control demonstrating that these credential-bearing files are excluded from source control. ### Attack Path 1. The user runs `node scripts/register.js`. 2. The returned API key is displayed in terminal output and saved in two plaintext files. 3. A local user, logging system, backup process, source-control operation, or accidentally shared project archive obtains ...[truncated 820 chars]
Remediation
## Remediation Suggestions - Do not print the complete API key. Display only a short masked fingerprint if confirmation is needed. - Store the key in one location rather than duplicating it in both JSON and `.env`. - Prefer an operating-system credential store or a dedicated secret-management facility. - If file storage is unavoidable, create the secret file with mode `0600` and verify ownership before writing. - Keep API keys out of `worker-config.json`; reserve that file for non-secret settings. - Replace an existing `.env` assignment instead of appending duplicate or historical credentials. - Add `.env` and any credential-bearing configuration to version-control and packaging ignore rules. - Provide key revocation and rotation instructions. - Warn users if the target secret file is group-readable, world-readable, tracked by source control, or a symbolic link.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/check-jobs.js:42
Finding
Configured Active-Bid Limit Is Not Enforced## Vulnerability Details **File Location**: `scripts/check-jobs.js:42-54` **Vulnerability Type**: Broken economic safety control and fail-open authorization logic **Risk Level**: Medium ### Vulnerable Code ```js // Auto-bid if enabled if (config.autoBid && scored.length > 0) { // Check how many active bids we have const profileRes = await fetch(`${API}/agents/me/profile`, { headers: { Authorization: `Bearer ${KEY}` }, }); const profile = await profileRes.json(); // Get our existing bids by checking each job let activeBids = 0; // Simple: just bid on top match if under limit if (activeBids < (config.maxActiveBids || 5)) { const topJob = scored[0]; ``` ### Technical Analysis The code states that it will check the number of active bids, but it never performs that calculation. Although an authenticated profile request is made, the resulting `profile` object is unused. The `activeBids` variable is unconditionally initialized to zero immediately before the limit comparison. Consequently, any positive `maxActiveBids` value causes the check to pass on every process invocation. In heartbeat or scheduled use, each invocation can submit another bid even after the configured limit has been reached. This defeats an explicit user-defined control intended to constrain autonomous marketplace commitments. The logic also uses `config.maxActiveBids || 5`, meaning a deliberately configured value of zero is replaced with five. Although `autoBid` must separately be enabled, zero cannot function as a defensive limit once automatic bidding is active. ### Attack Path 1. The user enables `autoBid` and configures `maxActiveBids` to constrain autonomous activity. 2. The script is invoked repeatedly through heartbeat processing or manual execution. 3. Each run initializes `activeBids` to zero instead of retrieving pending bids. 4. The comparison passes regardless of the account's actual number ...[truncated 896 chars]
Remediation
## Remediation Suggestions - Query a dedicated endpoint for the agent's pending or active bids before submitting a new bid. - Count only statuses that represent current commitments and compare that count to the configured limit. - Fail closed when the active-bid query fails, returns malformed data, or cannot be authenticated. - Use nullish handling rather than logical OR so a configured value of zero remains valid, for example: `config.maxActiveBids ?? 5`. - Validate that the limit is a non-negative integer. - Add idempotency protection to prevent repeated bidding on the same job. - Where supported, enforce the limit atomically on the server to avoid races between concurrent worker executions. - Add tests covering zero limits, exact-limit behavior, malformed API responses, concurrent invocations, and accounts already above the limit.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
While framed as a description mismatch, this instance points to undisclosed credential handling and automated economic actions: account registration, API-key storage, auto-bidding, and potential delivery on the user's behalf. When a skill can transact, communicate externally, and store credentials without prominent disclosure of those side effects, users may install it without understanding the operational and financial risk.

Ae1

High
Category
analysis-evasion
Content
node scripts/register.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/register.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `scripts/check-jobs.js` | Manually check for matching jobs |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
  console.log(`\n📝 Saved API key to worker-config.json`);

  // Also save to .env
  const envPath = path.join(__dirname, '..', '.env');
  fs.appendFileSync(envPath, `\nMOLT_API_KEY=${data.agent.api_key}\n`);
  console.log(`📝 Saved to .env`);
Confidence
95% confidence
Finding
Appending the API key to a project .env file creates a plaintext credential artifact in a common location that is frequently copied, backed up, or accidentally committed to source control. If leaked, the key could enable account takeover of the agent worker context, unauthorized job operations, or abuse of any associated balance or API privileges.

Credential Access

High
Category
Privilege Escalation
Content
console.log(`\n📝 Saved API key to worker-config.json`);

  // Also save to .env
  const envPath = path.join(__dirname, '..', '.env');
  fs.appendFileSync(envPath, `\nMOLT_API_KEY=${data.agent.api_key}\n`);
  console.log(`📝 Saved to .env`);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documents network access, webhook registration, API-key usage, and environment-file storage, but it declares no explicit tool scope or permissions. In an agent ecosystem, missing capability boundaries makes it easier for a skill to obtain broader-than-expected access to network and secrets, increasing the chance of unauthorized external communication or credential misuse.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill describes autonomous bidding and delivery but does not prominently warn that it may take external actions on the user's behalf. In a marketplace context, silent automation can commit the user to obligations, send messages, and submit work without meaningful review, creating financial, reputational, and data-leak risks if the agent behaves incorrectly.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script can automatically place bids via a POST request when config.autoBid is enabled, which is a state-changing action performed without an interactive confirmation step or a strong in-file warning. In the context of a freelancer marketplace worker, this can commit the user/account to engagements based solely on remote job data and local config, increasing the risk of unwanted financial, reputational, or operational consequences if misconfigured or abused.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The script loads an API key from worker-config.json or the MOLT_API_KEY environment variable and exits if it is missing, but there is no comment, help text, or other disclosure explaining that sensitive credentials will be accessed. For code files, access to credentials should have at least some visible warning or explanatory documentation unless already clearly disclosed elsewhere in the skill description.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This script sends arbitrary delivery content to a remote API endpoint without an explicit, immediate warning at the point of transmission. In the context of an auto-freelancing skill that may process local files or stdin, this increases the risk that users unknowingly upload sensitive data, proprietary content, or secrets to a third-party service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code sends the user's name, email, password, skills, and description to a remote HTTP endpoint. Although the script prints 'Registering...', it does not clearly disclose that sensitive registration data will be transmitted to an external service before submission.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script persists the returned API key into worker-config.json and appends it to .env without checking file permissions, warning the user, or using a secure secret store. On multi-user systems, shared repos, backups, or accidental commits, this can expose the credential and allow unauthorized use of the worker account or API actions.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This code makes an authenticated network request to a remote service using the user's API key, but provides no prior user-facing notice that account data will be sent to an external endpoint. The file contains error output, but no disclosure comment, prompt, or informational message describing the remote data access behavior.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The setup flow says registration saves an API key to .env but does not clearly warn about the sensitivity of that credential or safe handling practices. Users may accidentally commit the key to source control, expose it to other skills, or store it with overly broad local access, leading to account takeover or unauthorized marketplace actions.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The code reads MOLT_API_KEY from the environment, which is a sensitive credential source. Although using an API key is necessary here, the file does not include any user-facing explanation or warning about credential access or handling.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/bid.js:8

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/check-jobs.js:8

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/deliver.js:8

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/register.js:6

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/setup-webhook.js:9

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/status.js:8

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/register.js:44