Back to skill

Security audit

OpenServ Agent Sdk

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate OpenServ agent SDK skill, but it needs review because it normalizes plaintext wallet/API secrets and includes broad update, file, and deletion patterns without strong safeguards.

Install only after reviewing the secret and financial implications. Use a sandbox or dedicated project, keep .env out of version control, use a low-value dedicated wallet, avoid funding it until needed, pin package and skill versions where possible, and add your own confirmations/path validation around file upload and deletion capabilities.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:426
Finding

Unpinned Third-Party Packages and Remote npx Execution

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:35, SKILL.md:69-71, SKILL.md:426-435, reference.md:20, troubleshooting.md:165, examples/basic-agent.ts:7, examples/haiku-poet-agent.ts:7
Vulnerability Type: Supply-chain exposure through mutable package resolution and remote package execution
Risk Level: Medium

Vulnerable Code

bash
npm install @openserv-labs/sdk @openserv-labs/client zod
bash
npm init -y && npm pkg set type=module
npm i @openserv-labs/sdk @openserv-labs/client dotenv zod
npm i -D @types/node tsx typescript
bash
# Check if updates are available
npx skills check

# Update all installed skills to latest versions
npx skills update
bash
npx skills add openserv-labs/skills

The executable examples also direct users to invoke tsx through npx:

typescript
/**
 * Run with: npx tsx basic-agent.ts
 */

Technical Analysis

The installation instructions resolve dependencies without exact versions or integrity constraints. The audited project does not include a package manifest or lockfile that binds these commands to reviewed artifacts. Consequently, executing the documented commands at different times may install materially different package versions.

The npx commands create an additional execution risk. If the requested package is not already available locally, npx can download it from the configured registry and execute its entry point. The skills update and skills add operations can also replace or add executable instructions whose contents were not part of this audit.

This does not establish that the named packages are malicious. The vulnerability is that the documented workflow permits mutable, remotely supplied code and Skill content to execute without version pinning or review.

Attack Path

  1. An attacker compromises a relevant package release, publishing account, registry route, or trans ...[truncated 1068 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin every production and development dependency to an exact, reviewed version.
  2. Add and commit package.json and a package-manager lockfile.
  3. Prefer npm ci over mutable npm install operations in repeatable environments.
  4. Use npm ci --ignore-scripts where package lifecycle scripts are unnecessary and compatibility has been verified.
  5. Replace unversioned npx commands with locally installed, pinned executables or invoke an explicitly pinned package version.
  6. Verify registry provenance, package signatures or attestations, and integrity hashes where supported.
  7. Review the diff and source of Skill updates before installation rather than automatically updating all installed Skills.
  8. Run installation and update operations in a sandbox without production credentials or funded wallet keys.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:78
Finding

Blockchain Wallet Private Key Persisted in a Plaintext Environment File

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:17, SKILL.md:78-88, SKILL.md:357-389, reference.md:287-305, reference.md:331-340, troubleshooting.md:104-114, examples/env.example.txt:6-9
Vulnerability Type: Plaintext storage and process-wide loading of sensitive credentials
Risk Level: Medium

Vulnerable Code

The documented environment file contains slots for persistent wallet and platform credentials:

env
# Auto-populated by provision():
WALLET_PRIVATE_KEY=
OPENSERV_API_KEY=
OPENSERV_AUTH_TOKEN=
PORT=7378

The documented provisioning workflow explicitly reloads the generated private key and passes it to authentication and transaction-signing operations:

typescript
// Reload .env to pick up WALLET_PRIVATE_KEY written by provision()
dotenv.config({ override: true })

// Register on-chain (non-blocking — requires funded wallet on Base)
try {
  const client = new PlatformClient()
  await client.authenticate(process.env.WALLET_PRIVATE_KEY)

  const erc8004 = await client.erc8004.registerOnChain({
    workflowId: result.workflowId,
    privateKey: process.env.WALLET_PRIVATE_KEY!,
    name: 'My Service',
    description: 'What this agent does'
  })

The reference documentation confirms that the same key is also used for payments and credit top-ups:

env
OPENSERV_API_KEY=auto-populated
OPENSERV_AUTH_TOKEN=auto-populated
WALLET_PRIVATE_KEY=auto-populated (also used for x402 payments, USDC top-up, and ERC-8004 registration)

Technical Analysis

provision() is documented as writing a raw blockchain private key, an API key, and an authentication token into a project-level .env file. The application then reloads that file with override: true, placing the values into process-wide environment state.

A .env file is ordinary plaintext storage. The documentation does not enforce restrictive file permissions, confirm that the file is excluded ...[truncated 1704 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not persist raw wallet private keys in project-level plaintext files by default.
  2. Use an operating-system keychain, managed secret store, hardware wallet, remote signer, or cloud key-management service.
  3. Pass a signing interface to the application rather than exposing the raw private key wherever the SDK supports it.
  4. Ensure .env is explicitly listed in .gitignore, container ignore files, backup exclusions, and deployment packaging exclusions.
  5. Create secret files with owner-only permissions such as 0600 on supported systems.
  6. Use a dedicated, least-value wallet with limited funds and no unrelated assets.
  7. Avoid propagating wallet keys to child processes and redact all secret-bearing values from logs, telemetry, errors, and crash reports.
  8. Add startup checks that reject insecure secret-file permissions.
  9. Rotate platform credentials and transfer wallet-controlled assets immediately if the file may have been disclosed.

T09 · Insecure Skill Coding Practices

Warning
Location
examples/file-operations.ts:26
Finding

Unvalidated User-Controlled Workspace File Paths

Content
View full analysis

Vulnerability Details

File Location: examples/file-operations.ts:26-45 and examples/capability-with-agent-methods.ts:14-49
Vulnerability Type: Improper path validation for workspace uploads
Risk Level: Medium

Vulnerable Code

The saveFile capability passes a caller-controlled path directly to uploadFile():

typescript
agent.addCapability({
  name: 'saveFile',
  description: 'Save content to a file',
  inputSchema: z.object({
    path: z.string().describe('File path'),
    content: z.string().describe('File content')
  }),
  async run({ args, action }) {
    if (action?.type !== 'do-task') return 'No workspace context'

    const result = await this.uploadFile({
      workspaceId: action.workspace.id,
      path: args.path,
      file: args.content,
      taskIds: action.task ? [action.task.id] : undefined
    })

    return `File saved: ${result.fullUrl}`
  }
})

A second example derives a path from user-controlled topic input but only replaces whitespace:

typescript
inputSchema: z.object({
  topic: z.string().describe('Report topic'),
  format: z.enum(['brief', 'detailed']).optional()
}),

// ...

await this.uploadFile({
  workspaceId: workspace.id,
  path: `reports/${topic.replace(/\s+/g, '-').toLowerCase()}.txt`,
  file: report,
  taskIds: [task.id]
})

Technical Analysis

The schemas accept unrestricted strings for both path and topic. The values are forwarded to workspace file operations without normalization or checks for:

  • Absolute paths
  • .. traversal components
  • Forward or backward path separators
  • Encoded traversal sequences
  • Control characters
  • Reserved filenames
  • Unexpectedly long paths or content

Replacing whitespace in topic does not produce a safe filename because traversal components and separators remain intact. For example, a topic containing ../../target survives the transformation ...[truncated 1816 chars]

Remediation
View remediation

Remediation Suggestions

  1. Normalize all submitted paths before upload.
  2. Reject absolute paths, null bytes, control characters, empty segments, and any .. component.
  3. Reject both / and \ in values intended to be filenames.
  4. Resolve the candidate path against a fixed workspace prefix and verify that the normalized result remains inside that prefix.
  5. For generated reports, convert topic to a conservative filename allowlist such as lowercase ASCII letters, digits, hyphens, and underscores.
  6. Use a generated identifier for the stored filename and preserve the original topic only as metadata.
  7. Apply maximum lengths to path, topic, and content.
  8. Require explicit authorization before overwriting an existing workspace object.
  9. Enforce the same normalization, containment, size, and authorization rules on the server because client-side validation alone is not a security boundary.
  10. Add tests for Unix paths, Windows paths, encoded traversal, repeated separators, Unicode separator variants, and overwrite attempts.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The skill is described as an SDK for building/deploying agents, but the documented capabilities also include workspace file listing, upload, and deletion. This mismatch can mislead users about the operational power of resulting agents, increasing the chance that sensitive workspace data is exposed or modified unexpectedly.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

text
my-agent/
├── src/agent.ts
├── .env
├── .gitignore
├── package.json
└── tsconfig.json

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 76)May include surrounding context.

text
my-agent/
├── src/agent.ts
├── .env
├── .gitignore
├── package.json
└── tsconfig.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 169)May include surrounding context.

md
See `examples/capability-with-agent-methods.ts` for logging and file upload patterns.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The skill explicitly instructs reloading .env after provision() writes WALLET_PRIVATE_KEY, then using that private key for on-chain registration. Handling long-lived wallet private keys in plaintext env files materially increases the risk of credential theft via source control leaks, local compromise, logs, backups, or downstream tooling.

Content

Scanner excerpt · SKILL.md (reported line 379)May include surrounding context.

md
}
})

// Reload .env to pick up WALLET_PRIVATE_KEY written by provision()
dotenv.config({ override: true })

// Register on-chain (non-blocking — requires funded wallet on Base)

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The documented pattern reloads .env specifically to retrieve a previously written WALLET_PRIVATE_KEY, normalizing access to a plaintext private key from local disk. This creates a credential exposure path and broadens the blast radius because any local process, developer tooling, accidental commit, or host compromise may obtain a key capable of authenticating, paying, and registering on-chain identities.

Content

Scanner excerpt · reference.md (reported line 297)May include surrounding context.

md
// ... after provision() ...

// Reload .env to pick up WALLET_PRIVATE_KEY written by provision()
dotenv.config({ override: true })

try {

Credential Access

High
Category
Privilege Escalation
Confidence
71% confidence
Finding

The document instructs users to save a generated authentication token into .env, which encourages storage of a live secret in a plaintext file commonly replicated across developer machines, backups, and potentially source control. While this is common in local development, placing long-lived credentials in .env increases the risk of credential leakage and unauthorized agent access if the file is exposed.

Content

Scanner excerpt · troubleshooting.md (reported line 51)May include surrounding context.

typescript
const { authToken, authTokenHash } = await client.agents.generateAuthToken()
await client.agents.saveAuthToken({ id: agentId, authTokenHash })
// Save authToken to .env as OPENSERV_AUTH_TOKEN

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documents environment-variable handling, wallet creation, API key writing, and credential reload behavior, but it does not declare any explicit tool scope or permissions boundaries. In an agent-skill ecosystem, missing scope declarations weakens transparency and can enable broader-than-expected access to sensitive resources such as env-backed secrets.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explains that provision() writes API keys and wallet secrets into .env, but it does not prominently warn users to protect those credentials or keep them out of version control. This omission increases the likelihood of accidental secret exposure through commits, logs, or insecure file sharing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation includes a file deletion method but does not provide any safety guardrails, such as confirmation requirements, scoping restrictions, or warnings about destructive effects. In an agent context, exposing deletion primitives without safeguards can lead to accidental or unauthorized data loss.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The skill instructs users to run npx skills check without pinning a package version, which allows execution of whatever version is current at install time. This creates a supply-chain risk: a malicious or compromised upstream release could run arbitrary code on the user's machine.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The unpinned npx skills update command executes code from a non-version-locked package source. If the package or dependency chain is compromised, users may unknowingly execute attacker-controlled code during update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

The command npx skills add openserv-labs/skills references a remote package/resource without a pinned immutable version. This exposes users to dependency confusion or upstream compromise risks at execution time.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · examples/basic-agent.ts (reported line 54)May include surrounding context.

ts
}
  })

  console.log(`Webhook: https://api.openserv.ai/webhooks/trigger/${result.triggerToken}`)

  // 4. Run the agent - credentials already bound via provision()
  await run(agent)

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · reference.md (reported line 265)May include surrounding context.

md
}
  })

  console.log(`Webhook: https://api.openserv.ai/webhooks/trigger/${result.triggerToken}`)

  // 4. Run the agent - credentials already bound via provision()
  await run(agent)

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The documented capabilities go beyond agent construction/runtime support into wallet-funded USDC top-ups and ERC-8004 on-chain registration. Those financial and on-chain operations are not obviously required by the manifest's high-level purpose of building and deploying autonomous AI agents, especially within this SDK-focused skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The reference explicitly states that provision() writes WALLET_PRIVATE_KEY to .env at runtime and encourages reloading it into process environment state. Persisting a private key to a local plaintext config file materially increases the risk of credential theft via source control leakage, local compromise, backups, logs, or accidental sharing, especially because the same key is later used for payments and on-chain actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Automatically writing WALLET_PRIVATE_KEY to .env without strong upfront warning or explicit consent is unsafe secret handling. Users may assume environment files are local configuration artifacts, but plaintext wallet persistence can expose funds, identity, and payment authority if the file is committed, copied, or read by other tooling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The troubleshooting guide recommends lsof -ti:7378 | xargs kill -9, which forcefully terminates any process bound to that port without warning or verification. In documentation used by developers or operators, this can cause unintended service disruption or data loss if the port is occupied by an unrelated or critical process.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
reference.md:36

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
troubleshooting.md:16