Back to skill

Security audit

Openclaw Pqsafe

Security checks for vulnerabilities and agentic risk

Overview

This payment skill is not clearly malicious, but its implementation does not match important safety claims about revocation and exposes high-impact payment data through under-scoped network behavior.

Use this only in a sandbox or after source review. Before production use, require the publisher to make verify_envelope accurately enforce or clearly exclude revocation and nonce checks, restrict and authenticate revoke_envelope network destinations, minimize what is sent remotely, clarify secret-key handling, and update vulnerable development 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/index.ts:277
Finding

Revoked SpendEnvelopes Continue to Pass Local Verification

Content
View full analysis
{ const { verifyEnvelope } = await import('@pqsafe/agent-pay') const { hexToBytes } = await import('@noble/hashes/utils.js' as string) const overridePubKey = input.dsaPublicKey ? hexToBytes(input.dsaPublicKey) : undefined try { const envelope = verifyEnvelope(input.envelope, overridePubKey) return { valid: true, agent: envelope.agent, issuer: envelope.issuer, validUntil: new Date(envelope.validUntil * 1000).toISOString(), } ``` ### Technical Analysis The production verification path checks the envelope through the local `verifyEnvelope` dependency and immediately returns `valid: true` when cryptographic and temporal validation succeeds. It does not query a revocation registry, inspect a signed revocation snapshot, or otherwise determine whether the envelope has previously been revoked. This conflicts with the declared security model: - `SKILL.md` states that the real-time revocation list is checked on every verification. - `skill.json` states that an envelope will fail `verify_envelope` after revocation. The implementation therefore creates a fail-open authorization condition: a cryptographically valid but revoked payment authorization remains acceptable to any caller relying on this Skill's `valid` result. ### Attack Path 1. An issuer creates a valid signed SpendEnvelope authorizing an Agent to spend funds. 2. An attacker, compromised Agent, or recipient obtains the envelope while it is valid. 3. The issuer invokes `revoke_envelope`, and the remote registry records the revocation. 4. The attacker submits the original envelope to `verify_envelope`. 5. The Skill performs only local signature and time-window validation. 6. Because th ...[truncated 744 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.ts:319
Finding

Revocation Requests Can Disclose Complete Payment Envelopes to Insecure or Arbitrary Endpoints

Content
View full analysis
{ // Compute the SHA-256 envelope hash server-side by sending the full envelope. // The revocation endpoint accepts { envelopeJson, signature, dsaPublicKey, reason? }. const controller = new AbortController() const timer = setTimeout(() => controller.abort(), timeoutMs) let response: Response try { response = await fetch(`${apiUrl}/envelopes/revoke`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ signedEnvelope: input.envelope, reason: input.reason, }), signal: controller.signal, }) } finally { clearTimeout(timer) } if (!response.ok) { const body = await response.text().catch(() => '(no body)') throw new Error( `PQSafe: revoke request failed — HTTP ${response.status}: ${body}`, ) } ``` The destination is constructed without validation at `src/index.ts:394`: ```typescript const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '') ``` ### Technical Analysis The Skill posts the complete signed envelope and optional revocation reason to a caller-configurable base URL. No restriction requires HTTPS, validates the expected PQSafe hostname, or prevents loopback, link-local, private-network, or attacker-controlled destinations. The request contains potentially sensitive payment metadata inside `envelopeJson`, including the issuer, Agent identifier, spending limit, currency, recipient allowlist, payment rail, and validity window. It also includes the signature and public key. Sending the complete envelope is broader than necessary when rev ...[truncated 2438 chars]
Remediation
View remediation
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 (31)

Known Vulnerable Dependency: vitest==1.6.1 — 1 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed)

Critical
Category
Supply Chain
Confidence
94% confidence
Finding

vitest 1.6.1 is present and the advisory describes arbitrary file read and execution when the Vitest UI server is listening. That makes this a real and serious development-time risk: if enabled in a developer environment, especially on a shared or exposed host, it could lead to code execution even though it is not part of the production payment path.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vitest==1.6.1 — 1 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed)

Critical
Category
Supply Chain
Confidence
93% confidence
Finding

This package includes vitest 1.6.1, which is flagged with a critical advisory allowing arbitrary file read and execution when the Vitest UI server is listening. Even though vitest is a devDependency, exploitation could compromise developer workstations or CI runners during testing, which is especially sensitive in a payment-related skill where secrets, signing keys, or environment tokens may be present.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · README.md (reported line 64)May include surrounding context.

const result = await executeAgentPayment(envelope, { recipient: '0xdeadbeef...', amount: 9.50, memo: 'API access token', })

text

Known Vulnerable Dependency: nanoid==3.3.12 — 2 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)

High
Category
Supply Chain
Confidence
80% confidence
Finding

nanoid 3.3.12 is present transitively through postcss, and the cited issues concern denial-of-service conditions in specific non-secure or custom generator usage patterns. The vulnerable package version is present, so this is a genuine dependency risk, but in this lockfile context it is a build-tool transitive dependency and there is no evidence this skill uses the affected APIs directly.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: postcss==8.5.13 — 2 advisory(ies): CVE-2026-69153 (PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappi); CVE-2026-73646 (PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) l)

High
Category
Supply Chain
Confidence
89% confidence
Finding

postcss 8.5.13 is included and the reported advisories involve source map handling and path traversal behaviors during processing. Because this is part of the frontend/build toolchain rather than the payment protocol logic itself, exploitability depends on processing attacker-controlled CSS or source map references, but the dependency risk is real.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vite==5.4.21 — 3 advisory(ies): CVE-2026-39365 (Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling); CVE-2026-53571 (vite: `server.fs.deny` bypass on Windows alternate paths); CVE-2026-53632 (launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows)

High
Category
Supply Chain
Confidence
91% confidence
Finding

vite 5.4.21 is present and the listed advisories include path traversal and Windows-specific file access issues. This is a true vulnerable dependency, though its danger is moderated here because Vite is a dev dependency; exposure becomes more serious if developers run the dev server or related tooling on untrusted machines, networks, or Windows hosts.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 207)May include surrounding context.

ts
expect(process.env['PQSAFE_TEST_MODE']).toBe('true')

    // Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 209)May include surrounding context.

ts
expect(process.env['PQSAFE_TEST_MODE']).toBe('true')

    // Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 241)May include surrounding context.

ts
expect(process.env['PQSAFE_TEST_MODE']).toBe('true')

    // Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 208)May include surrounding context.

ts
// Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 210)May include surrounding context.

ts
// Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/skill.test.ts (reported line 242)May include surrounding context.

ts
// Temporarily remove any real API key env vars if present
    const savedApiKey = process.env['PQSAFE_API_KEY']
    const savedKeyId = process.env['PQSAFE_KEY_ID']
    delete process.env['PQSAFE_API_KEY']
    delete process.env['PQSAFE_KEY_ID']

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly describes capabilities to create signed payment authorizations and revoke them, but it does not prominently warn that these actions can authorize real spending or trigger irreversible state changes depending on rail and environment. In an agent-skill context, weak safety framing increases the risk of accidental misuse by operators or downstream agents who may invoke these operations without appreciating the financial consequences.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares environment-variable requirements and describes network-backed payment operations, but it does not define an explicit tool/permission scope such as allowed tools or permissions. In an agent setting, that weakens least-privilege controls and can let the runtime grant broader env or network access than users expect, which is especially risky for a payment-related skill handling API keys and live rail interactions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation states that revocation is real-time and that some payment rails are live in sandbox, but it does not prominently warn users that invoking these operations can have operational side effects, including invalidating envelopes or triggering real external payment/test-rail activity. For an agentic payment skill, unclear side-effect boundaries increase the chance of unintended financial or workflow disruption through accidental invocation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · README.md (reported line 157)May include surrounding context.

md
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · dist/cjs/index.cjs (reported line 240)May include surrounding context.

js
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · dist/index.d.ts (reported line 124)May include surrounding context.

ts
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · dist/index.js (reported line 204)May include surrounding context.

js
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · src/index.ts (reported line 153)May include surrounding context.

ts
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · src/index.ts (reported line 394)May include surrounding context.

ts
* (useful for local development and CI).
 */
export function createPQSafeOpenClawSkill(config = {}) {
    const apiUrl = (config.apiUrl ?? 'https://api.pqsafe.xyz/v1').replace(/\/$/, '');
    const timeoutMs = config.timeoutMs ?? 30_000;
    const testMode = process.env['PQSAFE_TEST_MODE'] === 'true';
    async function handleCreateEnvelope(input, ctx) {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest exposes an operation that creates payment authorization artifacts and accepts a raw ML-DSA secret key as input, but it does not prominently warn that this key is highly sensitive or that the resulting envelope grants real spending authority. In an agent-payment context, insufficient warning increases the chance that users or orchestrators pass production signing keys into untrusted automation flows, logs, or third-party runtimes, leading to unauthorized payments or key compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The revoke_envelope production path transmits the full signed envelope, including envelopeJson, signature, public key, and optional reason, to a remote PQSafe API. Even if this is functionally required for revocation, it is still an external disclosure of potentially sensitive payment authorization metadata, and callers are not given an explicit consent mechanism, redaction option, or local-hash alternative in the API surface.

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.

Known Vulnerable Dependency: esbuild==0.21.5 — 1 advisory(ies): GHSA-67mh-4wv8-2f99 (esbuild enables any website to send any requests to the development server and r)

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The lockfile pins esbuild 0.21.5, which is flagged for a dev-server request exposure issue. In this skill, esbuild appears only as a development dependency via Vite, so the issue is real but mainly affects local development workflows rather than production runtime of the payment skill.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.