Back to skill

Security audit

AIN - AI Node Plugin

Security checks for vulnerabilities and agentic risk

Overview

The plugin mostly matches its stated AIN routing purpose, but it can route prompts to unintended providers because the documented config path is ignored and routing is enabled by default.

Review this plugin before installing in any environment with sensitive prompts, private workspace context, regulated data, or strict provider allowlists. Do not rely on configPath to constrain providers until the implementation is fixed; consider disabling enableRouting and exposeTools, using only a trusted default AIN config, and pinning or independently verifying @felipematos/ain-cli before use. Update the dev dependency lockfile before building or testing from source.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.ts:10
Finding

Configured AIN Configuration Path Is Ignored

Content
View full analysis

Vulnerability Details

File Location: src/index.ts:10-12
Vulnerability Type: Configuration security-boundary bypass
Risk Level: Medium

Vulnerable Code

ts
async register(api: OpenClawPluginApi) {
  const pluginConfig = api.pluginConfig as AinPluginConfig;
  const config = loadConfig();

  registerAinProviders(api, config);

The plugin declares and documents a configPath setting, but it invokes loadConfig() without using pluginConfig.configPath. Consequently, an operator-supplied path intended to select a restricted or trusted AIN configuration has no effect.

The loaded configuration is subsequently used to register all configured providers. The routing hook and ain_run tool may then select those providers and transmit prompts or conversation messages to their configured endpoints.

Technical Analysis

A configuration path can act as a security boundary when separate files contain different providers, credentials, endpoint allowlists, or data-handling policies. Ignoring that option causes the plugin to use the dependency's default configuration—documented as ~/.ain/config.yaml—instead of the operator-selected file.

This is a fail-open configuration error. The plugin reports successful registration without warning that the requested configuration was not used. The same behavior exists in the distributed runtime at dist/index.js:10-12.

Attack Path

  1. An operator configures configPath to point to a restricted AIN configuration containing only approved providers.
  2. The plugin ignores this value and calls loadConfig() with no path.
  3. A different default AIN configuration is loaded from the environment.
  4. Providers in that default configuration are registered with OpenClaw.
  5. The automatic routing hook or an invocation of ain_run selects one of those providers.
  6. Prompt, system-message, or conversation data is transmitted to an endpoint the operator did not intend ...[truncated 768 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pass the configured path to the AIN configuration loader using the API supported by @felipematos/ain-cli.
  2. Validate that configPath, when supplied, is a non-empty string and resolves to the intended file.
  3. Fail closed if an explicitly requested configuration cannot be read or parsed; do not silently fall back to the default configuration.
  4. Log the resolved configuration path without logging provider credentials or other secrets.
  5. Consider restricting configuration paths to an operator-approved directory if untrusted parties can modify plugin configuration.
  6. Add tests verifying that:
    • A custom configPath is passed to the loader.
    • An invalid explicit path prevents registration.
    • Providers from the default configuration are not registered when a custom configuration is selected.
  7. Rebuild dist/index.js after applying the source fix.

T08 · Insecure Dependencies

Note
Location
package-lock.json:441
Finding

Runtime Dependency Lockfile Resolves AIN CLI Through an External Monorepo Link

Content
View full analysis

Vulnerability Details

File Location: package-lock.json:24-28 and package-lock.json:441-444
Vulnerability Type: Non-reproducible and unsafe runtime dependency source
Risk Level: Low

Vulnerable Code

json
"../..": {
  "name": "@felipematos/ain-cli",
  "version": "0.11.0",
  "license": "MIT",
  "dependencies": {
json
"node_modules/@felipematos/ain-cli": {
  "resolved": "../..",
  "link": true
},

The lockfile represents the core runtime dependency as a filesystem link to ../.., outside the audited project, rather than as an immutable registry artifact with a package integrity hash.

The plugin delegates configuration loading, provider adapter creation, prompt execution, task classification, complexity estimation, and automatic routing to this dependency. Therefore, the effective security behavior substantially depends on whichever code is available at that external path.

Technical Analysis

A lockfile is expected to make dependency resolution reproducible. A relative link to a directory outside the package does not cryptographically identify the dependency contents and allows behavior to vary according to the surrounding filesystem.

This appears consistent with a lockfile generated inside a monorepo, but it is unsuitable as a standalone release lockfile. The root lockfile metadata also identifies the project as version 0.2.0, while package.json and plugin runtime metadata identify version 0.2.2, indicating stale release metadata.

No evidence was found that the linked AIN dependency is itself malicious. The finding concerns the unsafe and non-reproducible dependency resolution mechanism.

Attack Path

  1. A build, test, or installation workflow uses this lockfile in an environment where ../.. exists.
  2. An attacker with write access to that parent directory replaces or modifies the linked package.
  3. The package manager links the modified directory as `@f ...[truncated 1174 chars]
Remediation
View remediation

Remediation Suggestions

  1. Regenerate package-lock.json in a standalone package environment so @felipematos/ain-cli resolves to an npm registry artifact.
  2. Ensure the lock entry includes an exact version, registry URL, and SHA-512 integrity value.
  3. Replace the runtime semver range with an exact reviewed release where stronger reproducibility is required.
  4. Synchronize the package version across package.json, package-lock.json, and runtime plugin metadata.
  5. In CI, use npm ci with a clean workspace and reject runtime dependencies whose lock entries use unexpected filesystem links, Git sources, or missing integrity metadata.
  6. Review and scan the resolved @felipematos/ain-cli artifact because it executes inside the OpenClaw process and handles credentials and prompt data.
  7. Generate release artifacts from a clean environment and verify their dependency provenance before publication.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (22)

Known Vulnerable Dependency: vitest==2.1.9 — 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
94% confidence
Finding

vitest 2.1.9 is a real vulnerable dependency with advisories for arbitrary file read and possible execution when the Vitest UI server is running, plus the @vitest/mocker traversal issue. Because this package can start local test/UI services and interact with project files, the skill context makes it more dangerous for developers or CI environments that run tests, even though it is not a production runtime dependency.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vitest==2.1.9 — 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
95% confidence
Finding

If the project resolves to a Vitest release affected by the cited advisories, test infrastructure could permit arbitrary file read and possibly code execution when the Vitest UI server or mocking features are exposed. Although Vitest is a devDependency, compromise of CI or developer environments can still be severe, especially if tests run with repository secrets or broad filesystem access.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · dist/tools.js (reported line 5)May include surrounding context.

js
import { run, classifyTask, estimateComplexity } from '@felipematos/ain-cli';
export function registerAinTools(api) {
    api.registerTool({
        name: 'ain_run',
        description: 'Execute an LLM prompt through AIN with provider routing and structured output support',
        parameters: {
            type: 'object',
            properties: {
                prompt: { type: 'string', description: 'The prompt to send to the LLM' },
                provider: { type: 'string', description: 'Provider name (optional)' },
                model: { type: 'string', description: 'Model ID or alias (optional)' },
                jsonMode: { type: 'boolean', description: 'Request JSON output' },
                schema: { type: 'object', description: 'JSON schema for st

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · src/tools.ts (reported line 7)May include surrounding context.

ts
import { run, classifyTask, estimateComplexity } from '@felipematos/ain-cli';
export function registerAinTools(api) {
    api.registerTool({
        name: 'ain_run',
        description: 'Execute an LLM prompt through AIN with provider routing and structured output support',
        parameters: {
            type: 'object',
            properties: {
                prompt: { type: 'string', description: 'The prompt to send to the LLM' },
                provider: { type: 'string', description: 'Provider name (optional)' },
                model: { type: 'string', description: 'Model ID or alias (optional)' },
                jsonMode: { type: 'boolean', description: 'Request JSON output' },
                schema: { type: 'object', description: 'JSON schema for st

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
84% confidence
Finding

nanoid 3.3.11 is present and flagged for multiple denial-of-service style flaws involving invalid size handling and overflow conditions. In this file it is a transitive dev dependency via postcss/vite tooling, so the vulnerability is real, but practical impact depends on whether attacker-controlled input can reach the affected nanoid code paths during tooling execution.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: postcss==8.5.8 — 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
87% confidence
Finding

postcss 8.5.8 is a real vulnerable dependency with advisories including file-read and XSS-related issues. In this project it is a dev dependency brought in through Vite, so exposure is mostly during build/dev processing of attacker-controlled CSS or source map content rather than during normal runtime use of the skill.

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 has several known vulnerabilities including path traversal and Windows-specific filesystem or UNC-path issues. Although marked dev-only, Vite often runs a local server and processes files dynamically, which makes these issues more actionable in developer environments, especially if untrusted projects or requests are involved.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README advertises prompt execution, provider bridging, and intelligent routing to AIN providers but does not clearly warn that user prompts and possibly sensitive context may be transmitted to external third-party model providers. This can mislead operators into enabling the plugin or its tools without understanding the data egress and privacy implications, increasing the risk of unintended disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill exposes ain_run, which sends prompts through AIN's execution and routing layers and may forward user input to any configured provider, yet the documentation does not warn users that prompt contents can be analyzed and transmitted to third-party or local/remote backends. This omission creates a real privacy and data-handling risk because operators may unknowingly use the tool with sensitive prompts under incorrect assumptions about where data is processed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The routing section describes automatic prompt analysis and model selection via a before_model_resolve hook, but it does not disclose the security/privacy implications of inspecting prompts and dynamically redirecting them to different providers. In an agent ecosystem, this can materially change system behavior and data exposure boundaries, especially when users expect a fixed model/provider path.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This hook forwards the full context.prompt to an external routing function, which likely transmits user prompt content outside the local process boundary. Even if intended for model selection, this creates a data exposure risk because sensitive user input may be disclosed to a third-party service without any minimization, consent, or visibility at this integration point.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The ain_run tool forwards arbitrary prompt content, optional system prompts, and schemas to an external LLM provider via run(...), but this file provides no disclosure, consent, or data-classification guardrails. In an agent-skill context, this can cause sensitive user or workspace data included in prompts to be transmitted off-box to third-party providers unexpectedly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The hook forwards the full user prompt to an external routing function, which may disclose sensitive prompt contents to another service or component without any visible notice, consent, or minimization in this code path. In an LLM plugin context, prompts often contain secrets, personal data, or proprietary material, so sending them off-box for routing expands the data exposure surface.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The ain_run tool forwards arbitrary prompt and optional system content to an external LLM provider via run(...) without any visible consent, warning, redaction, or policy gating. In an agent-skill context, this can cause sensitive user or workspace data to be exfiltrated to third-party model providers if upstream callers pass confidential content into the tool.

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 · test/plugin.test.ts (reported line 17)May include surrounding context.

ts
},
      openai: {
        kind: 'openai-compatible',
        baseUrl: 'https://api.openai.com/v1',
        apiKey: 'sk-test',
        models: [{ id: 'gpt-4o' }],
        timeoutMs: 60000,

Known Vulnerable Dependency: @vitest/mocker==2.1.9 — 1 advisory(ies): CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Low
Category
Supply Chain
Confidence
88% confidence
Finding

@vitest/mocker 2.1.9 is a real vulnerable dependency per the cited advisory, but it is a dev/test-only package used by Vitest rather than production runtime code. In this lockfile context, exploitation generally requires running the affected test tooling or exposing related functionality during development, so the issue is real but less dangerous for an installed skill package than a runtime dependency would be.

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
90% confidence
Finding

esbuild 0.21.5 has a known development-server vulnerability, and the package-lock confirms that exact version is present. However, esbuild is marked dev-only here and the cited issue affects the dev server surface, so risk is mainly during local development if a developer runs a vulnerable server in a hostile network/browser context.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
85% confidence
Finding

The runtime dependency uses a caret version range, which allows newer minor/patch releases to be installed without explicit review. This increases supply-chain risk because a compromised or breaking upstream release could be pulled into consumers of the plugin unexpectedly.

Content

Scanner excerpt · package.json (reported line 25)May include surrounding context.

json
"prepublishOnly": "npm run build && npm run test"
  },
  "dependencies": {
    "@felipematos/ain-cli": "^0.11.0"
  },
  "peerDependencies": {
    "openclaw": ">=1.0.0"

Unverifiable Dependency: openclaw has 16 known advisory(ies) (CVE-2026-53846 (OpenClaw: Workspace .env npm_execpath could influence bundled runtime dependency); CVE-2026-32064 (OpenClaw's andbox browser noVNC observer lacked VNC authentication); CVE-2026-32006 (OpenClaw has a BlueBubbles group allowlist mismatch via DM pairing-store fallbac) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 36)May include surrounding context.

json
}
  },
  "devDependencies": {
    "typescript": "^5.5.0",
    "vitest": "^2.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 37)May include surrounding context.

json
},
  "devDependencies": {
    "typescript": "^5.5.0",
    "vitest": "^2.0.0"
  }
}

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This code file includes a credential-like value (apiKey: 'sk-test') in a provider configuration. Although it is clearly a test value, there is no nearby comment or docstring explaining that a credential-like token is being used only as a mock, which fits the code-file warning criterion for sensitive credential access/disclosure.

Content

No source excerpt is available for this finding.