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## 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
## 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## 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
## 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.

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.

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
Content
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
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

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
Content
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
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

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.

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.

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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

External Transmission

Medium
Category
Data Exfiltration
Content
},
      openai: {
        kind: 'openai-compatible',
        baseUrl: 'https://api.openai.com/v1',
        apiKey: 'sk-test',
        models: [{ id: 'gpt-4o' }],
        timeoutMs: 60000,
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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.

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.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"prepublishOnly": "npm run build && npm run test"
  },
  "dependencies": {
    "@felipematos/ain-cli": "^0.11.0"
  },
  "peerDependencies": {
    "openclaw": ">=1.0.0"
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.

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.

Unpinned Dependencies

Low
Category
Supply Chain
Content
}
  },
  "devDependencies": {
    "typescript": "^5.5.0",
    "vitest": "^2.0.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "devDependencies": {
    "typescript": "^5.5.0",
    "vitest": "^2.0.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Missing User Warnings

Low
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.

Static analysis

No suspicious patterns detected.