Back to skill

Security audit

Harbor — Curated and shared Memory for AI Agents

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent memory and credential-management purpose, but it asks for high-impact credential and persistence access while documenting misleading credential isolation and unexpected cloud account behavior.

Install only if you are comfortable giving Harbor persistent memory access and credential-broker authority. Prefer pinned audited versions, avoid `harbor auth get` in agent/tool code, use low-scope dedicated API tokens, review what gets remembered before enabling sync, and expect the recommended plugin to create a cloud account on first load.

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

other

Error
Location
SKILL.md:57
Finding
Automatic Cloud Account Creation Contradicts the Declared Opt-In Network Model<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:57-64` and `SKILL.md:223-232` **Vulnerability Type**: Undisclosed automatic external registration **Risk Level**: High ### Vulnerable Code ```markdown ### Cloud sync is opt-in - Default: **fully local**, no network calls - `harbor cloud enable`: provisions free account (50 memories) for cross-device sync - `harbor cloud disable`: opts out permanently, deletes cloud config - **Plugin behavior**: creates a cloud account on first load (for credential setup page to work), but **no data is synced until you actively call `harbor remember`**. The account alone does not transmit any user data. ``` ```markdown ## OpenClaw Plugin (recommended) For deeper integration, install the Harbor OpenClaw plugin: ```bash openclaw plugins install github.com/oSEAItic/harbor/plugins/harbor-openclaw --link ``` The plugin: - Registers `harbor_remember` + `harbor_recall` as native OpenClaw agent tools - Syncs Harbor context to your workspace on session start (auto-indexed by OpenClaw) - Captures context before compaction (prevents memory loss) - Creates a cloud account on first load (enables credential setup page). **No data synced until you call `harbor remember`**. Opt out: `harbor cloud disable` ``` ### Technical Analysis The document declares that Harbor is fully local by default and that cloud synchronization is opt-in. However, the recommended plugin creates a cloud account automatically on first load rather than waiting for the user to run `harbor cloud enable`. The endpoint disclosure elsewhere in the file states that authentication requests transmit a device fingerprint hash and setup tokens. Consequently, account provisioning necessarily entails network communication and metadata disclosure, even if memory records and credentials are not synchronized at that point. This conflicts with the statements that the default has “no network calls” and that account creation transmits no user data. Automatic registra ...[truncated 1189 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic account creation in the default plugin configuration. 2. Require an explicit user action, such as `harbor cloud enable`, before making any registration or authentication request. 3. Display an informed-consent prompt listing: - The exact destination endpoints. - Every transmitted field. - The purpose and retention period of each field. - The service hosting region. 4. Correct the documentation so “fully local, no network calls” applies only when no plugin registration traffic occurs. 5. Provide a strict offline mode that technically prevents all outbound connections. 6. Allow users to use the credential setup workflow locally without first provisioning a cloud account. 7. Provide a mechanism to delete automatically created accounts and associated authentication metadata. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:122
Finding
Authenticated HTTP Proxy Does Not Document Destination Binding for Stored Credentials<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:106-109`, `SKILL.md:122-133`, and `SKILL.md:309-316` **Vulnerability Type**: Unrestricted credential-bearing HTTP proxy **Risk Level**: High ### Vulnerable Code ```markdown | Tool | What it does | |------|-------------| | `harbor_http` | Auth-proxy HTTP — call any API without exposing credentials | | `harbor_remember` | Save context that persists across sessions | | `harbor_recall` | Search and retrieve past context | | `harbor_learn_schema` | Teach Harbor which API fields matter — reduces noise permanently | ``` ```json { "url": "https://api.github.com/repos/oSEAItic/harbor", "auth": "github-pat", "auth_header": "Authorization: Bearer" } ``` ```markdown - `auth` — credential name in Harbor's keychain - `auth_header` — how to inject the credential (default: `Authorization: Bearer`). For custom headers: `"x-cg-pro-api-key"`, `"X-API-Key"`, etc. - Responses go through the full pipeline: memory, schema learning, context injection ``` ```bash # 1. User stores credential (once) harbor auth <name> # 2. Tool retrieves key (any injection format) harbor auth get <name> # raw key to stdout # 3. Or let Harbor inject into header automatically harbor fetch <url> --auth <name> # header-based APIs ``` ### Technical Analysis The documented proxy interface accepts a caller-controlled URL, credential name, and authentication-header format. It is explicitly described as able to “call any API.” The reviewed documentation does not describe any of the following safeguards: - Binding a credential to one or more approved origins. - Restricting which skill may use each credential. - Requiring confirmation when a credential is used with a new destination. - Rejecting cross-origin redirects. - Preventing credentials from being sent over plaintext HTTP. - Restricting access to loopback, link-local, or cloud metadata addresses. Credential isolation is not achieved merely by hiding the secret val ...[truncated 1481 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind each credential to an explicit allowlist of HTTPS origins at enrollment time. 2. Match destinations using normalized scheme, host, and port values rather than substring checks. 3. Reject plaintext HTTP whenever credentials are attached. 4. Reject cross-origin redirects or remove authentication headers before following them. 5. Require explicit user confirmation before first use with any new origin. 6. Enforce per-skill access-control lists so one skill cannot use credentials enrolled for another. 7. Restrict caller-controlled authentication headers to predefined templates associated with each credential. 8. Block loopback, private, link-local, metadata-service, and Unix-socket destinations unless separately authorized. 9. Avoid exposing credential names globally; use opaque, capability-scoped handles. 10. Log destination, credential handle, caller identity, and authorization decision without recording secret values. 11. Add automated tests for attacker-controlled URLs, DNS rebinding, redirect chains, URL parsing ambiguities, and header injection. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:205
Finding
Raw Credential Retrieval Through Standard Output Breaks Credential Isolation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:205-217`, `SKILL.md:239-274`, and `SKILL.md:309-313` **Vulnerability Type**: Plaintext credential exposure to agent-accessible processes **Risk Level**: High ### Vulnerable Code ```bash harbor auth <name> # Store credential harbor auth get <name> # Retrieve credential (stdout) harbor auth sync # Sync cloud → local ``` ```typescript export const tavily_search = { name: "tavily_search", description: "Web search via Tavily (credential-isolated through Harbor)", parameters: { type: "object", required: ["query"], properties: { query: { type: "string" } }, }, async execute({ query }: { query: string }) { const { execSync } = require("node:child_process"); const key = execSync("harbor auth get tavily", { encoding: "utf-8" }); const res = await fetch("https://api.tavily.com/search", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: key, query, max_results: 5 }), }); return res.json(); }, }; ``` ```typescript export const stripe_balance = { name: "stripe_balance", description: "Check Stripe balance (credential-isolated)", parameters: { type: "object", properties: {} }, async execute() { const { execSync } = require("node:child_process"); const key = execSync("harbor auth get stripe", { encoding: "utf-8" }); const res = await fetch("https://api.stripe.com/v1/balance", { headers: { Authorization: `Bearer ${key}` }, }); return res.json(); }, }; ``` ### Technical Analysis The `harbor auth get` command returns the complete plaintext credential through standard output. The examples then copy that value into a JavaScript string controlled by the tool process. This behavior contradicts the stated security property that skills never see raw API keys. On ...[truncated 1493 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `harbor auth get` from all agent-accessible and skill-accessible interfaces. 2. Do not return plaintext credentials through stdout, tool responses, environment variables, temporary files, or command-line arguments. 3. Implement body and query-parameter authentication inside the trusted Harbor broker rather than handing secrets to tool code. 4. Represent credentials using opaque handles that authorize only a specific service, origin, method, and injection template. 5. Require per-skill authorization and explicit user approval before granting access to a credential handle. 6. Keep secret material inside a minimal trusted process and zero sensitive buffers when practical. 7. Redact credential values from logs, traces, exceptions, diagnostics, and model-visible output. 8. Deprecate existing raw retrieval behavior and warn users to rotate credentials previously exposed to tool processes. 9. Update the documentation so security claims distinguish encrypted storage from actual runtime credential isolation. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:19
Finding
Executable Dependencies Are Installed From Mutable Unpinned Sources<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:19-22`, `SKILL.md:80-86`, and `SKILL.md:223-227` **Vulnerability Type**: Unpinned executable supply-chain dependency **Risk Level**: Medium ### Vulnerable Code ```yaml install: - kind: go package: github.com/oseaitic/harbor@latest bins: [harbor] ``` ```markdown If `harbor` is not installed: ```bash go install github.com/oseaitic/harbor/cmd/harbor@latest ``` ``` ```markdown For deeper integration, install the Harbor OpenClaw plugin: ```bash openclaw plugins install github.com/oSEAItic/harbor/plugins/harbor-openclaw --link ``` ``` ### Technical Analysis The installation instructions resolve Harbor using the mutable `@latest` selector. The recommended plugin installation is also not pinned to a release or commit. Therefore, the executable code installed by users may differ from the code that was reviewed when this skill file was published. Although the document mentions signed Git tags, the installation commands do not pin or automatically verify a specific signed tag, commit, checksum, or reproducible build artifact. A compromised upstream account, repository, dependency chain, or future malicious release could alter the installed behavior without any change to this skill package. The downloaded executable receives access to `~/.harbor/`, credentials, persistent memory, OS keychain facilities, and optional network functionality. This makes dependency integrity particularly important. ### Attack Path 1. An attacker compromises the upstream repository, release workflow, maintainer account, or one of its build dependencies. 2. The attacker publishes a modified version that becomes the revision selected by `@latest`, or modifies the unpinned plugin source. 3. A user follows the documented installation command. 4. The package manager downloads and builds the attacker-controlled revision. 5. The resulting executable or plugin runs under the user account. 6. Malicious code accesses Harb ...[truncated 618 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `@latest` with a specific audited semantic version or immutable commit hash. 2. Pin the OpenClaw plugin independently to an immutable release or commit. 3. Publish and verify cryptographic checksums for release artifacts. 4. Automatically verify the expected signed Git tag rather than merely mentioning that signed tags exist. 5. Maintain a lock file or equivalent dependency manifest for reproducible builds. 6. Document the exact source revision and dependency graph used for each release. 7. Use a trusted build pipeline with provenance attestations and narrowly scoped publishing credentials. 8. Review and update pinned versions through a controlled security-update process. 9. Avoid `--link` installation from a mutable source unless the exact linked revision is verified. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Memory Manipulation

High
Category
Memory Poisoning
Content
harbor get <connector.resource> --param key=value         # Connector fetch
harbor remember <topic> "Your analysis summary"             # Save context
harbor remember --connector <name> <topic> "summary"       # Scoped to connector
harbor forget mem_xxx                                      # Delete memory
harbor recall --search "keyword"                          # Search memory
harbor auth <name>                                        # Store credential
harbor auth get <name>                                    # Retrieve credential (stdout)
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The skill repeatedly claims that skills or tool code never see raw API keys, but later documents `harbor auth get`, which returns credentials to stdout and into the calling process. That inconsistency can mislead users and developers into adopting weaker patterns under the impression they still have strong credential isolation.

External Transmission

Medium
Category
Data Exfiltration
Content
# Agent prompt: "Enter API key for github-pat:"

# Call API through Harbor — agent never sees the key
harbor fetch https://api.github.com/repos/oSEAItic/harbor --auth github-pat
```

Or via MCP tool:
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# Agent prompt: "Enter API key for github-pat:"

# Call API through Harbor — agent never sees the key
harbor fetch https://api.github.com/repos/oSEAItic/harbor --auth github-pat
```

Or via MCP tool:
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# Agent prompt: "Enter API key for github-pat:"

# Call API through Harbor — agent never sees the key
harbor fetch https://api.github.com/repos/oSEAItic/harbor --auth github-pat
```

Or via MCP tool:
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Ssd 3

Medium
Confidence
93% confidence
Finding
The skill encourages persistent storage of agent-generated summaries and auto-injection of prior context across sessions, with optional cloud sync of memories and schemas. In practice, users and agents often summarize sensitive prompts, investigation details, credentials-adjacent data, or proprietary content into natural language, so this creates a real cross-session data leakage and unintended retention risk.

Ssd 3

Medium
Confidence
94% confidence
Finding
Syncing workspace/session context on start and capturing context before compaction normalizes broad collection of conversational state that may contain secrets, regulated data, or confidential analysis. Even if framed as convenience, the plugin context makes this more dangerous because agents routinely process mixed-sensitivity information and users may not realize it is being persisted or prepared for sync.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
This section states that tool code never touches raw API keys, then immediately introduces a mode where tools call `harbor auth get` and receive the raw key. In an agent skill ecosystem, that defeats the advertised isolation boundary and may cause operators to install the skill with incorrect trust assumptions.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
Examples labeled as credential-isolated fetch secrets into the Node.js process via `execSync("harbor auth get ...")`. Once the secret is in-process, any compromised dependency, logging, exception trace, subprocess, or malicious skill code can exfiltrate it, so the example undermines the claimed security model.

External Transmission

Medium
Category
Data Exfiltration
Content
async execute({ query }: { query: string }) {
    const { execSync } = require("node:child_process");
    const key = execSync("harbor auth get tavily", { encoding: "utf-8" });
    const res = await fetch("https://api.tavily.com/search", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ api_key: key, query, max_results: 5 }),
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
async execute({ query }: { query: string }) {
    const { execSync } = require("node:child_process");
    const key = execSync("harbor auth get tavily", { encoding: "utf-8" });
    const res = await fetch("https://api.tavily.com/search", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ api_key: key, query, max_results: 5 }),
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
async execute() {
    const { execSync } = require("node:child_process");
    const key = execSync("harbor auth get stripe", { encoding: "utf-8" });
    const res = await fetch("https://api.stripe.com/v1/balance", {
      headers: { Authorization: `Bearer ${key}` },
    });
    return res.json();
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The markdown explicitly says to always pass "OpenClaw Agent" as the author, which imposes a fixed natural-language value rather than offering user choice. This is a locale/language-style policy concern because it hardcodes one labeling convention without opt-in or justification.

Static analysis

No suspicious patterns detected.