Grades are a hygiene check, not a security guarantee.

MCP, MCP server

UltraMemory

One memory across Claude, ChatGPT, Cursor, Gemini CLI, Codex & Hermes — recalls first every turn and says "I don't know" instead of guessing.

Compatibility: Not stated.

Grade B

Minor issues only, no Medium or High. Worth a quick look at the findings below before installing.

Graded by PlugVetRubric v2

Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.

Rescanned at commit f759e5fa4920, unchanged since the check below.

PERMISSION_DELETE_FILES NETWORK_NO_FIXED_HOST SECRETS_PATH_DOTENV SECRETS_ENV_READ

Why this grade

  • PERMISSION_DELETE_FILES Low

    Contains a call that can delete files.

    autoconfig.py, line 735 p = subprocess.run(argv, capture_output=True, text=True, timeout=timeout)

  • NETWORK_NO_FIXED_HOST Low

    Makes a network call whose host is not written as a fixed address.

    cli.py, line 438 data = urllib.request.urlopen(raw + "/" + name, timeout=30).read() # noqa: S310

  • SECRETS_PATH_DOTENV Low

    Mentions a .env file.

    __init__.py, line 431 # only non-secret fields land here; api_key lives in $HERMES_HOME/.env

  • SECRETS_ENV_READ Note

    Reads an environment variable whose name contains KEY, SECRET, TOKEN, PASSWORD or CREDENTIAL.

    cli.py, line 246 key = (args.key or os.environ.get("ULTRAMEMORY_API_KEY") or "").strip()

Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.

Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.

What was checked

Plain notes from the hygiene checks.

  • Permissions

    Concern

    can delete files.

    PERMISSION_DELETE_FILES

    autoconfig.py, line 735

    p = subprocess.run(argv, capture_output=True, text=True, timeout=timeout)

    autoconfig.py, line 1991

    os.remove(path)

    autoconfig.py, line 2321

    shutil.rmtree(d, ignore_errors=True)

    Show more

    cli.py, line 273

    rc = subprocess.run([hpy, "-c", "import ultramemory"], capture_output=True, timeout=10).returncode

    cli.py, line 443

    return subprocess.call(["bash", path, *passthrough])

    cli.py, line 454

    return subprocess.call(["bash", path, *(["--check"] if action == "check" else [])])

    test_autoconfig.py, line 337

    proc = subprocess.run(

    test_autoconfig.py, line 736

    proc = subprocess.run(

    test_autoconfig.py, line 780

    proc = subprocess.run(

    test_autoconfig.py, line 948

    p = subprocess.run(

    uninstall.sh, line 49

    else: os.remove(f)

    uninstall.sh, line 65

    os.remove(f)

    uninstall.sh, line 123

    os.remove(p); print(" removed %s (the apply created it; empty after restore)"%p); continue

  • Install and update

    Pass

    No install-time script found, and dependencies are pinned or absent.

  • Network

    Concern

    can reach a host that is not written as a fixed address.

    NETWORK_NO_FIXED_HOST

    cli.py, line 438

    data = urllib.request.urlopen(raw + "/" + name, timeout=30).read() # noqa: S310

    cli.py, line 657

    with urllib.request.urlopen(req, timeout=20) as resp: # noqa: S310

    install.sh, line 4

    # bash <(curl -fsSL https://ultramemory.io/kit.sh) # interactive

    Show more

    install.sh, line 5

    # bash <(curl -fsSL https://ultramemory.io/kit.sh) --tier 3 --non-interactive # CI (reads $ULTRAMEMORY_API_KEY)

    install.sh, line 6

    # bash <(curl -fsSL https://ultramemory.io/kit.sh) --dry-run # print the plan, change nothing

    install.sh, line 7

    # bash <(curl -fsSL https://ultramemory.io/kit.sh) --uninstall # remove what the kit installed

    install.sh, line 59

    fetch(){ # relpath dest - write to a same-dir temp, then atomically rename (new inode; a running hook keeps its old bytes)

    install.sh, line 63

    else curl -fsSL "$REPO_RAW/$rel" -o "$tmp" || { rm -f "$tmp"; return 1; }; fi

    install.sh, line 177

    code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 \

    install.sh, line 300

    mkdir -p "$UM_DIR"; curl -fsSL "$REPO_RAW/uninstall.sh" -o "$un" || die "could not fetch uninstall.sh"

    install.sh, line 322

    command -v curl >/dev/null 2>&1 || die "curl is required"

    install.sh, line 356

    c_info "Uninstall anytime: bash <(curl -fsSL https://ultramemory.io/kit.sh) --uninstall"

    agent-kit/hooks/capture-hook.sh, line 21

    command -v curl >/dev/null 2>&1 || exit 0 # fail-open if prerequisites are missing

  • Secrets

    Concern

    reads a credential or environment file.

    SECRETS_ENV_READ SECRETS_PATH_DOTENV

    __init__.py, line 431

    # only non-secret fields land here; api_key lives in $HERMES_HOME/.env

    cli.py, line 10

    1. writes ``ULTRAMEMORY_API_KEY=<key>`` into ``$HERMES_HOME/.env`` (chmod 600) - the secret

    cli.py, line 246

    key = (args.key or os.environ.get("ULTRAMEMORY_API_KEY") or "").strip()

    Show more

    cli.py, line 55

    """Idempotently set ``KEY=value`` in a ``.env`` file: replace an existing assignment in place,

    cli.py, line 176

    $HERMES_HOME/.env (ULTRAMEMORY_API_KEY), which `ultramemory enable` writes.

    cli.py, line 258

    # 1) secret -> $HERMES_HOME/.env (never the JSON)

    cli.py, line 259

    env_path = os.path.join(hermes_home, ".env")

    cli.py, line 338

    print("Note: ULTRAMEMORY_API_KEY remains in $HERMES_HOME/.env - remove it manually if desired.")

    cli.py, line 358

    key = key or (os.environ.get("ULTRAMEMORY_API_KEY") or "").strip()

    cli.py, line 490

    key = (os.environ.get("ULTRAMEMORY_API_KEY") or "").strip()

    cli.py, line 725

    help="override $HERMES_HOME (where .env / config.yaml live)",

    agent-kit/hooks/recall-first-hook.sh, line 181

    headers={"Authorization": "Bearer " + os.environ.get("UM_API_KEY", ""), "Content-Type": "application/json"},

    agent-kit/hooks/recall-first-hook.sh, line 286

    headers={"Authorization": "Bearer " + os.environ.get("UM_API_KEY", ""), "Content-Type": "application/json"},

    hooks/recall-first-hook.sh, line 181

    headers={"Authorization": "Bearer " + os.environ.get("UM_API_KEY", ""), "Content-Type": "application/json"},

    hooks/recall-first-hook.sh, line 286

    headers={"Authorization": "Bearer " + os.environ.get("UM_API_KEY", ""), "Content-Type": "application/json"},

  • Agent instructions

    Pass

    No instruction to ignore earlier instructions or to hide a step.

  • Obfuscation

    Pass

    No encoded or minified payload found.

  • Licence

    Pass

    A licence file is present (LICENSE).

  • Maintainer activity

    Pass

    The latest commit is within the last 365 days.

Note

Hygiene check of commit f759e5fa4920. can delete files. can reach a host that is not written as a fixed address. reads a credential or environment file.

Date and source

Date checked:

View source

github.com

Commit graded: f759e5fa492012a8546f174229b62a2cf9f25628

This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.

Read how this letter is chosen