Back to skill

Security audit

MemHub

Security checks across malware telemetry and agentic risk

Overview

MemHub is a disclosed memory-and-Git-sync skill, but users should treat it as a persistent personal-data store that can sync to GitHub or Gitee.

Install only if you want an agent to keep durable memory for you. Review what it stores, avoid saving secrets or sensitive personal data, and use token/SSH or a broker you trust if you are uncomfortable with the default OAuth broker. If remote sync is enabled, remember that memory may be pushed to your GitHub/Gitee repository and retained in Git history.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (27)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs the agent to read environment variables, read and write local files, invoke shell commands, and access network services, yet no explicit permissions are declared. That mismatch increases the chance an agent platform or reviewer underestimates the skill’s authority, especially because the commands include repository mutation, credential handling, and remote sync.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill is designed to obtain OAuth credentials through a third-party broker service (`oauth.1024hub.cn`). That broker can observe authorization flow metadata and may be able to issue or handle tokens for the user's GitHub/Gitee account, which is highly sensitive because the same account may protect private code and memory repositories.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The code routes OAuth through a broker by default, but this behavior is not surfaced prominently at the operation site and appears inconsistent with the skill description. Users may believe sync only talks to GitHub/Gitee, while in reality authorization is mediated by an external service, preventing informed consent for credential handling.

Vague Triggers

Medium
Confidence
86% confidence
Finding
The trigger phrases include broad everyday expressions such as '记住这个' and '帮我记一下', which can cause the skill to activate during routine conversation rather than only during clearly consented memory operations. In this skill’s context, accidental activation is more dangerous because activation can lead to persistent storage and remote synchronization of user data.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
After `remember`, `promote`, and `forget`, the tool may automatically push memory contents to a remote Git repository via `maybe_auto_push` without an upfront per-operation warning. Because this skill manages cross-agent memory that may contain personal or project-sensitive information, silent transmission materially increases privacy and data-exfiltration risk.

Ssd 3

Medium
Confidence
96% confidence
Finding
The skill is designed to write cross-agent memory containing user preferences, facts, and decisions, and also to export that data for chatbot injection. This creates a real retention and disclosure risk because sensitive natural-language data can be accumulated over time and later surfaced to other agents or contexts beyond the user’s immediate expectation.

Ssd 3

Medium
Confidence
95% confidence
Finding
The instructions encourage storing key decisions, preferences, and facts at session end and synchronizing them to remote storage. That workflow semantically pressures broad collection of conversation content and onward transfer to GitHub/Gitee, which can expose user data beyond the local environment and preserve it indefinitely in Git history.

Ssd 3

Medium
Confidence
97% confidence
Finding
The agent protocol says to load long-term memory at conversation start and use it as injected chatbot context. This is dangerous because it normalizes automatic resurfacing of previously stored personal data into future model prompts and outputs, increasing cross-session privacy leakage and the blast radius of any bad or over-collected memory.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
meta = PROVIDERS[provider]
    if explicit_token:
        return explicit_token
    if os.environ.get(meta["env_token"]):
        return os.environ[meta["env_token"]]
    secrets = load_secrets(repo)
    token = ((secrets.get("sync") or {}).get(provider) or {}).get("token")
Confidence
70% confidence
Finding
os.environ.get(meta["env_token

Env Variable Harvesting

High
Category
Data Exfiltration
Content
# for both GitHub and Gitee with no per-user configuration. A developer can
    # still opt into a direct flow by passing --client-secret (Gitee) or by
    # explicitly disabling the broker via --broker-url "" .
    explicit_secret = client_secret or os.environ.get(meta.get("env_client_secret", ""))
    if not explicit_secret:
        broker = resolve_broker_url(provider, broker_url)
        if broker:
Confidence
70% confidence
Finding
os.environ.get(meta.get("env_client_secret

Credential Access

High
Category
Privilege Escalation
Content
1. CLI 调 broker 创建授权 session,拿到 `auth_url`;
2. CLI 打开该 URL,用户在 GitHub/Gitee 页面点击确认授权;
3. broker 在服务端用 `client_secret` 换取 token;
4. CLI 轮询 broker 拿到 token,存入本地 `.memhub/secrets.yaml`(git 忽略)。

无浏览器环境加 `--no-browser`,CLI 会打印 URL 供手动打开。
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
`init`/`sync` 会自动注册结构化 merge 驱动(local git config 不随 clone 走,故每台设备首次
`sync` 会自愈补注册),多设备对同一记忆文件的并发追加可自动合并,不会冲突。

> **换新机器/新 Agent 时**:凭据(token)存在本机 `.memhub/secrets.yaml` 且不随 git 同步,
> 所以新机器即使 clone 了记忆仓库也需要**重新授权一次**。先跑 `doctor` 自检,按提示补齐
> remote/token 即可——全绿后自动同步即就绪。
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
1. CLI 调用 broker 创建授权 session,得到一个 `auth_url`。
2. CLI 打开(或打印)该 URL;Agent 应把 URL 展示给用户,请用户在浏览器完成授权。
3. CLI 轮询 broker 直到拿到 access token,自动存入本机 `.memhub/secrets.yaml`(git 忽略)。
4. 不要要求用户把 access token 发到聊天里。

无浏览器环境:加 `--no-browser`,CLI 会打印 URL 由用户手动打开。
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
## 发布与安全约束

- 不要把真实 token、client secret、OAuth code 写进 `SKILL.md`、README、示例或提交历史。
- `.memhub/secrets.yaml` 必须保持本地忽略。
- 发布到 SkillHub/ClawHub 的包应包含:`SKILL.md`、`README.md`、`scripts/memhub.py`、`templates/context-pack.md.j2`。
- 发布包不应包含 `__pycache__`、`.pyc`、`.git` 或用户个人记忆数据。
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
- GitHub/Gitee remote 只是同步后端;YAML/Markdown 文件仍是可信源数据。
- 自动写入默认进入 canonical 记忆(本地提交,不自动推送);低置信或需人工复核的才用 `--inbox`。
- `sync setup` 会触发授权、创建仓库、修改 remote;**只有用户明确要求配置/切换同步时才执行**。
- OAuth/token/SSH 凭据、authorization code、client secret、access token 都属于敏感信息;不要在回答中复述。

### 对话开始:读取上下文
Confidence
70% confidence
Finding
access token

Credential Access

High
Category
Privilege Escalation
Content
1. CLI 调用 broker 创建授权 session,得到一个 `auth_url`。
2. CLI 打开(或打印)该 URL;Agent 应把 URL 展示给用户,请用户在浏览器完成授权。
3. CLI 轮询 broker 直到拿到 access token,自动存入本机 `.memhub/secrets.yaml`(git 忽略)。
4. 不要要求用户把 access token 发到聊天里。

无浏览器环境:加 `--no-browser`,CLI 会打印 URL 由用户手动打开。
Confidence
70% confidence
Finding
access token

Credential Access

High
Category
Privilege Escalation
Content
1. CLI 调用 broker 创建授权 session,得到一个 `auth_url`。
2. CLI 打开(或打印)该 URL;Agent 应把 URL 展示给用户,请用户在浏览器完成授权。
3. CLI 轮询 broker 直到拿到 access token,自动存入本机 `.memhub/secrets.yaml`(git 忽略)。
4. 不要要求用户把 access token 发到聊天里。

无浏览器环境:加 `--no-browser`,CLI 会打印 URL 由用户手动打开。
Confidence
70% confidence
Finding
access token

Credential Access

High
Category
Privilege Escalation
Content
write_yaml(repo / "relations/tools.yaml", {"schema_version": SCHEMA_VERSION, "tools": []})
    write_yaml(repo / f"timeline/{today_month()}.yaml", {"schema_version": SCHEMA_VERSION, "month": today_month(), "events": []})

    gitignore = """# MemHub generated local indexes/caches and secrets\n.memhub/cache/\n.memhub/indexes/\n.memhub/secrets.yaml\n.memhub/secrets/\n*.db\n.DS_Store\n"""
    write_text(repo / ".gitignore", gitignore)
    write_text(repo / ".gitattributes", GITATTRIBUTES_CONTENT)
    ensure_merge_driver_registered(repo)
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
def secrets_path(repo: Path) -> Path:
    return repo / ".memhub/secrets.yaml"


def load_config(repo: Path) -> dict[str, Any]:
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
def ensure_gitignore_secret(repo: Path) -> None:
    path = repo / ".gitignore"
    existing = path.read_text(encoding="utf-8") if path.exists() else ""
    additions = [".memhub/secrets.yaml", ".memhub/secrets/"]
    changed = False
    for item in additions:
        if item not in existing.splitlines():
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
save_config(repo, cfg)
    commit_all(repo, f"memhub: configure {provider} sync")
    if auth_method == "oauth":
        credential_line = "OAuth token is stored locally in .memhub/secrets.yaml and ignored by git."
    elif auth_method == "token":
        credential_line = "Token is stored locally in .memhub/secrets.yaml and ignored by git."
    else:
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
if auth_method == "oauth":
        credential_line = "OAuth token is stored locally in .memhub/secrets.yaml and ignored by git."
    elif auth_method == "token":
        credential_line = "Token is stored locally in .memhub/secrets.yaml and ignored by git."
    else:
        credential_line = "SSH auth selected; no token stored by MemHub."
    return "\n".join([
Confidence
70% confidence
Finding
secrets.yaml

Credential Access

High
Category
Privilege Escalation
Content
def load_dotenv_files(paths: list[Path]) -> None:
    """Load simple KEY=VALUE lines from .env files without overriding existing env vars.

    This is intentionally tiny and dependency-free. It supports optional leading
    `export`, quoted values, blank lines, and comments. It never prints values.
Confidence
60% confidence
Finding
.env

Credential Access

High
Category
Privilege Escalation
Content
def main(argv: list[str] | None = None) -> int:
    load_dotenv_files([Path.cwd() / ".env", Path.home() / ".env"])
    parser = argparse.ArgumentParser(prog="memhub", description="MemHub Protocol v0.1 reference CLI")
    parser.add_argument("--repo", default=os.environ.get("MEMHUB_REPO", "./memhub-data"), help="MemHub repository path")
    sub = parser.add_subparsers(dest="cmd", required=True)
Confidence
60% confidence
Finding
.env"

Credential Access

High
Category
Privilege Escalation
Content
def main(argv: list[str] | None = None) -> int:
    load_dotenv_files([Path.cwd() / ".env", Path.home() / ".env"])
    parser = argparse.ArgumentParser(prog="memhub", description="MemHub Protocol v0.1 reference CLI")
    parser.add_argument("--repo", default=os.environ.get("MEMHUB_REPO", "./memhub-data"), help="MemHub repository path")
    sub = parser.add_subparsers(dest="cmd", required=True)
Confidence
60% confidence
Finding
.env"

VirusTotal

61/61 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/memhub.py:2310