Back to skill

Security audit

HipoolMemorySystem

Security checks for vulnerabilities and agentic risk

Overview

This is a real local agent-memory database, but its shipped C persistence code has unsafe filesystem handling that users should review before installing.

Install only after reviewing or patching the filesystem-safety issues. Run it as an unprivileged user in a private workspace, use a trusted data directory, restrict shard names to simple alphanumeric/underscore/dash values, and avoid running the benchmark/test scripts on shared hosts until their shell cleanup is replaced with safer directory handling.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
memory.c:986
Finding

Unvalidated Shard Names Permit Filesystem Path Escape

Content
View full analysis
shard_count >= MAX_SHARDS) { fprintf(stderr,"max shards (%d) reached\n",MAX_SHARDS); return NULL; } int idx = ctx->shard_count; strncpy(ctx->shards[idx].name, name, 63); ctx->shards[idx].name[63] = '\0'; /* 子数据目录: data_dir/shard_/ */ char sd[1024]; snprintf(sd, sizeof(sd), "%s/shard_%s", ctx->data_dir, name); MemoryCtx *sc = (MemoryCtx*)calloc(1, sizeof(MemoryCtx)); if (!sc) return NULL; ctx->shards[idx].ctx = sc; ctx->shard_count++; /* 小池: 256KB 每个 shard */ sc->wal_disabled = 1; if (pool_init(&sc->pool, SHARD_POOL_SIZE) < 0) { free(sc); ctx->shard_count--; return NULL; } hash_init(&sc->table); tag_init(&sc->tag_index); sl_init(&sc->sorted); strncpy(sc->data_dir, sd, sizeof(sc->data_dir)-1); sc->file_ttl = ctx->file_ttl; sc->initialized = 1; /* 加载 shard 的持久化数据 */ ovf_load(sc); ovf_clean(sc); char wf[1024]; wal_path(wf, sizeof(wf), sd); int restored = wal_replay(sc, wf); wal_compact(wf); ``` ### Technical Analysis The shard name is accepted directly from the `--shard` argument or the `shard create` command and interpolated into a filesystem path. There is no validation preventing path separators, traversal components, or names that resolve through attacker-controlled symbolic links. The resulting path is assigned to `sc->data_dir` and used by the WAL, snapshot, loading, cleanup, and eviction subsystems. In particular, `wal_compact()` opens the generated `wal.log` path in truncating mode. Later operatio ...[truncated 2063 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
memory.c:676
Finding

Predictable Persistence Paths Allow Symlink-Based Overwrite and Destructive Path Replacement

Content
View full analysis
data_dir); int mkr = mkdir(ctx->data_dir,0755); if (mkr!=0 && errno!=EEXIST) { if (errno==ENOTDIR) { unlink(ctx->data_dir); mkdir(ctx->data_dir,0755); } } /* 收集活跃条目 */ MemEntry *to_evict[MAX_ENTRIES]; int n_evict = 0; for (int b=0; btable.b[b]; while (n) { MemEntry *e=n->e; if ((e->flags & FLAG_ACTIVE) && n_evict < MAX_ENTRIES) to_evict[n_evict++] = e; n=n->next; } } if (n_evict == 0) return 0; /* Pass 1: 写入磁盘 */ FILE *fp = fopen(fn,"w"); if (!fp) return -1; ``` Related unsafe behavior also occurs in the daily-file path at `memory.c:759-788`: ```c int mkr = mkdir(ctx->data_dir, 0755); if (mkr != 0 && errno != EEXIST) { if (errno == ENOTDIR) { unlink(ctx->data_dir); mkdir(ctx->data_dir, 0755); } } FILE *fp = fopen(tmp_fn, "w"); if (!fp) return -1; /* ... write records ... */ if (rename(tmp_fn, fn) != 0) { unlink(tmp_fn); return -1; } ``` The duplicated implementation in `memory_test.c:658-769` contains the same unsafe patterns. ### Technical Analysis Persistence files are created under predictable names such as: - `memory_snapshot.json` - `.tmp_memory-YYYY-MM-DD.json` - `memory-YYYY-MM-DD.json` - `wal.log` The implementation uses pathname-based `fopen(..., "w")`, which follows symbolic links and truncates the resolved target. It does not validate the ownership or type of the data directory or target file. The directory recovery logic is also destructive. If `mkdir(ctx->data_dir, 0755)` fails with `ENOTDIR`, the program calls `unlink(ctx->data_dir)` and attempts to replace that path w ...[truncated 1915 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
memory.c:709
Finding

Full Flush Leaves Dangling SkipList Pointers to Freed Slab Entries

Content
View full analysis
tag_index, e); hash_remove(&ctx->table, e->key_hash, (char*)e+sizeof(MemEntry)); e->flags = 0; pool_free(&ctx->pool, e); if (ctx->pool.ec > 0) ctx->pool.ec--; } return w; ``` The daily eviction implementation correctly removes the same entry from the SkipList before freeing it: ```c tag_remove_all(&ctx->tag_index, e); hash_remove(&ctx->table, e->key_hash, (char*)e + sizeof(MemEntry)); sl_remove(&ctx->sorted, e); e->flags = 0; pool_free(&ctx->pool, e); ``` ### Technical Analysis `ovf_flush()` removes each active entry from the tag index and hash table, then returns its slab allocation to the pool. It does not remove the entry from `ctx->sorted`. Consequently, SkipList nodes continue to contain pointers to freed `MemEntry` objects. Because the custom slab allocator can reuse the released slots, those pointers may subsequently reference: - Freed memory whose contents are no longer valid. - A different newly allocated entry. - Partially overwritten metadata. Range and date searches traverse the SkipList and dereference these pointers. This creates a use-after-free condition and can also corrupt logical index consistency. The omission is confirmed by comparison with `ovf_flush_day()`, which calls `sl_remove()` before `pool_free()`. ### Attack Path 1. The process stores one or more entries, causing them to be added to the hash table, tag index, and SkipList. 2. An API consumer invokes `memory_flush()` or another path that calls `ovf_flush()`. 3. `ovf_flush()` writes entries to the snapshot and frees their slab allocations without deleting their SkipList nodes. 4. The process remains alive and either: - Performs a range or date search, or - Stores new entries that reuse the ...[truncated 1062 chars]
Remediation
View remediation
tag_index, e); hash_remove(&ctx->table, e->key_hash, (char *)e + sizeof(MemEntry)); sl_remove(&ctx->sorted, e); e->flags = 0; pool_free(&ctx->pool, e); ``` 2. Centralize entry removal in one internal function so hash, tag, SkipList, flags, counters, and slab state cannot diverge. 3. Ensure the removal operation has a clearly documented and consistent lock requirement. 4. Add regression tests that: - Insert entries. - Call `memory_flush()`. - Perform range and date searches without destroying the context. - Insert replacement entries to force slab reuse. - Repeat the sequence under AddressSanitizer and UndefinedBehaviorSanitizer. 5. Add invariant checks confirming that `ctx->sorted.count`, hash-table count, and active-entry count remain consistent after flush and eviction. ]]>
Vulnerability Patterns
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (114)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · README.md (reported line 44)May include surrounding context.

text
memory set     <key> <value> [--tags a,b,c] [--ts <unix_sec>]    Store
memory get     <key>                                                 Read
memory del     <key>                                                 Delete
memory search  <query>                                               Text search
memory search  --tag <tag>                                           Tag search
memory search  --date YYYY-MM-DD                                     Date search

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 226)May include surrounding context.

md
- 消融脚本: `ablation_test.sh`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 102)May include surrounding context.

sh
# 3a. 正常 WAL 写 + 恢复
./memory set wal_a "survive" --tags w >/dev/null 2>&1
rm -f memory_data/memory_snapshot.json
r=$(./memory get wal_a 2>/dev/null)
[ "$r" = "survive" ] && OK "3a WAL 基本恢复" || FAIL "3a WAL 恢复: '$r'"

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 129)May include surrounding context.

sh
# 3a. 正常 WAL 写 + 恢复
./memory set wal_a "survive" --tags w >/dev/null 2>&1
rm -f memory_data/memory_snapshot.json
r=$(./memory get wal_a 2>/dev/null)
[ "$r" = "survive" ] && OK "3a WAL 基本恢复" || FAIL "3a WAL 恢复: '$r'"

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 139)May include surrounding context.

sh
# 3a. 正常 WAL 写 + 恢复
./memory set wal_a "survive" --tags w >/dev/null 2>&1
rm -f memory_data/memory_snapshot.json
r=$(./memory get wal_a 2>/dev/null)
[ "$r" = "survive" ] && OK "3a WAL 基本恢复" || FAIL "3a WAL 恢复: '$r'"

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 159)May include surrounding context.

sh
# 3a. 正常 WAL 写 + 恢复
./memory set wal_a "survive" --tags w >/dev/null 2>&1
rm -f memory_data/memory_snapshot.json
r=$(./memory get wal_a 2>/dev/null)
[ "$r" = "survive" ] && OK "3a WAL 基本恢复" || FAIL "3a WAL 恢复: '$r'"

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 323)May include surrounding context.

sh
/tmp/hipool_mt set mt "mt_val" >/dev/null 2>&1
r=$(/tmp/hipool_mt get mt 2>/dev/null)
[ "$r" = "mt_val" ] && OK "6j Mutex 版" || FAIL "6j Mutex: '$r'"
rm -f /tmp/hipool_mt

# 6k. snapshot 拒绝(mutex 模式)
gcc -O2 -DHIPOOL_USE_MUTEX memory.c -o /tmp/hipool_mt -lpthread 2>&1

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · ablation_test.sh (reported line 329)May include surrounding context.

sh
/tmp/hipool_mt set mt "mt_val" >/dev/null 2>&1
r=$(/tmp/hipool_mt get mt 2>/dev/null)
[ "$r" = "mt_val" ] && OK "6j Mutex 版" || FAIL "6j Mutex: '$r'"
rm -f /tmp/hipool_mt

# 6k. snapshot 拒绝(mutex 模式)
gcc -O2 -DHIPOOL_USE_MUTEX memory.c -o /tmp/hipool_mt -lpthread 2>&1

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This is a true unsafe-command finding because the program executes rm -rf /tmp/bench_hipool via the shell. While the path is fixed and appears intended for benchmark cleanup, shelling out for destructive deletion is fragile and can be dangerous in adversarial or shared environments.

Content

Scanner excerpt · bench_compare.c (reported line 57)May include surrounding context.

text
}

static MemoryCtx *hipool_new(void) {
    system("rm -rf /tmp/bench_hipool");
    MemoryCtx *c = (MemoryCtx*)calloc(1, sizeof(MemoryCtx));
    memory_init(c, "/tmp/bench_hipool", 7);
    return c;

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This is a true unsafe-command finding because the program executes rm -rf /tmp/bench_hipool via the shell. While the path is fixed and appears intended for benchmark cleanup, shelling out for destructive deletion is fragile and can be dangerous in adversarial or shared environments.

Content

Scanner excerpt · bench_compare.c (reported line 57)May include surrounding context.

text
}

static MemoryCtx *hipool_new(void) {
    system("rm -rf /tmp/bench_hipool");
    MemoryCtx *c = (MemoryCtx*)calloc(1, sizeof(MemoryCtx));
    memory_init(c, "/tmp/bench_hipool", 7);
    return c;

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This is a true unsafe-command finding because the program executes rm -rf /tmp/bench_hipool via the shell. While the path is fixed and appears intended for benchmark cleanup, shelling out for destructive deletion is fragile and can be dangerous in adversarial or shared environments.

Content

Scanner excerpt · bench_compare.c (reported line 57)May include surrounding context.

text
}

static MemoryCtx *hipool_new(void) {
    system("rm -rf /tmp/bench_hipool");
    MemoryCtx *c = (MemoryCtx*)calloc(1, sizeof(MemoryCtx));
    memory_init(c, "/tmp/bench_hipool", 7);
    return c;

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The same unsafe deletion primitive is used during teardown. In skill or agent contexts, any embedded capability to recursively delete directories is more dangerous because such code may be reused or executed in broader environments than the original benchmark author anticipated.

Content

Scanner excerpt · bench_compare.c (reported line 66)May include surrounding context.

text
memory_flush(c);
    memory_destroy(c);
    free(c);
    system("rm -rf /tmp/bench_hipool");
}

static void bench_hipool(int val_sz) {

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The same unsafe deletion primitive is used during teardown. In skill or agent contexts, any embedded capability to recursively delete directories is more dangerous because such code may be reused or executed in broader environments than the original benchmark author anticipated.

Content

Scanner excerpt · bench_compare.c (reported line 66)May include surrounding context.

text
memory_flush(c);
    memory_destroy(c);
    free(c);
    system("rm -rf /tmp/bench_hipool");
}

static void bench_hipool(int val_sz) {

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The same unsafe deletion primitive is used during teardown. In skill or agent contexts, any embedded capability to recursively delete directories is more dangerous because such code may be reused or executed in broader environments than the original benchmark author anticipated.

Content

Scanner excerpt · bench_compare.c (reported line 66)May include surrounding context.

text
memory_flush(c);
    memory_destroy(c);
    free(c);
    system("rm -rf /tmp/bench_hipool");
}

static void bench_hipool(int val_sz) {

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · bench_lmdb.py (reported line 30)May include surrounding context.

python
for val_size in VAL_SIZES:
        env_path = f"/tmp/bench_lmdb_{val_size}"
        os.system(f"rm -rf {env_path}")
        
        env = lmdb.open(env_path, map_size=104857600, metasync=False, sync=False)  # 100MB, no fsync
        samples_set = []

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · bench_lmdb.py (reported line 72)May include surrounding context.

python
for val_size in VAL_SIZES:
        env_path = f"/tmp/bench_lmdb_{val_size}"
        os.system(f"rm -rf {env_path}")
        
        env = lmdb.open(env_path, map_size=104857600, metasync=False, sync=False)  # 100MB, no fsync
        samples_set = []

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · bench_lmdb.py (reported line 82)May include surrounding context.

python
for val_size in VAL_SIZES:
        db_path = f"/tmp/bench_sqlite_{val_size}.db"
        os.system(f"rm -f {db_path}")
        
        conn = sqlite3.connect(db_path)
        conn.execute("PRAGMA synchronous=OFF")

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · bench_lmdb.py (reported line 126)May include surrounding context.

python
for val_size in VAL_SIZES:
        db_path = f"/tmp/bench_sqlite_{val_size}.db"
        os.system(f"rm -f {db_path}")
        
        conn = sqlite3.connect(db_path)
        conn.execute("PRAGMA synchronous=OFF")

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 29)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 66)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 29)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 66)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 29)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · bench_small.c (reported line 66)May include surrounding context.

text
}

static void bench(int vs, const char *label) {
    system("rm -rf /tmp/hb_small");
    MemoryCtx ctx;
    memory_init(&ctx, "/tmp/hb_small", 7);
    uint64_t *s_set = (uint64_t*)calloc(N, 8);

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The wildcard deletion rm -rf /tmp/bv4_* is the most concerning command in the file because it can remove multiple matching directories or files beyond the current test instance. In an agent skill context, automatic execution of broad deletion commands is more dangerous because the user may not realize local filesystem state will be altered.

Content

Scanner excerpt · bench_v4.c (reported line 56)May include surrounding context.

text
int sz = tests[ti].size, n = tests[ti].n;
        S sset, sget; sset.n=sget.n=0;
        char dir[64]; snprintf(dir,64,"/tmp/bv4_%d",ti);
        system("rm -rf /tmp/bv4_*");
        MemoryCtx ctx; memory_init(&ctx,dir,7);
        char key[64], val[16384];
        const char *tags[]={"bt"};

Static analysis

No suspicious patterns detected.