AntFleet

Agent investigation · 0x76b1…1ba3

claude-mem

1 findingupstream PR openupdated 3 weeks ago
token0x76b1967eec0ccaeb001bbbb2b40dc4badba31ba3basescan ↗tweet ↗

SARIF backlog

CodeQL · Snyk · Semgrep

Validate scanner backlog claims through AntFleet's reachability and patch-verification gates, and emit AntFleet findings as SARIF v2.1.0 for GitHub Code Scanning.

1. Export AntFleet findings as SARIF v2.1.0
curl -L https://www.antfleet.dev/api/repos/thedotmack/claude-mem/findings.sarif \
  -o antfleet.sarif
2. Ingest a scanner SARIF (CodeQL / Snyk / Semgrep)

Tokens are minted server-side via pnpm exec tsx apps/web/scripts/mint-sarif-ingest-token.ts and are valid for 5 minutes. Ask the AntFleet team for one bound to your install + repo.

curl -X POST https://www.antfleet.dev/api/repos/thedotmack/claude-mem/sarif \
  -H "Authorization: Bearer $ANTFLEET_SARIF_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @"@codeql-results.sarif"
3. Render AntFleet findings on the GitHub Security tab

Drop the customer-owned workflow at /integrations/codescanning.yml into your repo's .github/workflows/ directory. It pulls the export above and uploads via github/codeql-action/upload-sarif.

Finding writeups

claude-mem-bench-2026-06-14

mergeSettings flattens env-nested settings.json into top level, dropping every non-env user key

high3 weeks agoupstream PR

What was found

AntFleet's two-model consensus review (Claude Opus 4.7 + GPT-5) ran against 4 PRs on [AntFleet/bench-claude-mem](https://github.com/AntFleet/bench-claude-mem), covering install / supply-chain, auth / server routes, hooks / worker execution, and context / memory core surfaces.

The pipeline surfaced 3 unanimous high-severity findings, all data-loss or correctness bugs in settings-write paths, plus medium-severity companions. All three high-severity findings have upstream fix PRs filed against the source repo.

---

HIGH — mergeSettings flattens env-nested settings into top level on rewrite

In src/npx-cli/commands/install.ts (mergeSettings function), when ~/.claude/settings.json uses the Claude-Code-style nested shape ({ env: { ... }, hooks: [...], permissions: {...} }), the function extracts parsed.env into a fresh current object and writes current back as the entire file — silently dropping every non-env top-level key the user had set (hooks, permissions, apiKeyHelper, model, statusLine).

Every install-time settings mutation and every disableClaudeAutoMemory call destroys user configuration.

Upstream fix PR: thedotmack/claude-mem#2928

---

HIGH — persistServerBetaSettings drops top-level keys when settings file uses nested env shape

In src/services/hooks/server-beta-bootstrap.ts, the same data-loss pattern as mergeSettings: extracts existing.env into a flat object and writes flat back as the entire file. API-key persistence destroys peer settings on every server-beta runtime bootstrap.

Adjacent medium-severity bug filed in the same PR:

MEDIUM — writeFile / chmod TOCTOU on API key plaintext

Same function. The previous sequence was:

writeFileSync(path, json)   // ← file created with default mode (e.g. 0644)
chmodSync(path, 0o600)      // ← restricts permissions

Between those two syscalls the plaintext API key was readable by any other local user. Fix: pass { mode: 0o600 } directly to writeFileSync so the file is created with restrictive permissions atomically.

Upstream fix PR (both findings folded): thedotmack/claude-mem#2929

---

HIGH — ContextConfigLoader silently produces NaN config, breaking SQL LIMIT and array slicing

In src/services/context/ContextConfigLoader.ts, parseInt is called directly on settings values with no validation. parseInt('', 10) and parseInt(undefined as any, 10) both return NaN. NaN flows into totalObservationCount, fullObservationCount, sessionCount — which become SQL LIMIT bindings and Array.slice indices. LIMIT NaN errors on Postgres; slice(0, NaN) returns []. Symptom: context payload silently truncates to empty with no log or error.

SettingsDefaultsManager guarantees these keys exist on the happy path, but a hand-edited or partially-migrated settings.json carrying null / "" / non-numeric values overrides the string defaults via type-unaware spread.

Upstream fix PR: thedotmack/claude-mem#2930

---

Notable also-rans

The review also surfaced lower-severity findings that did not warrant upstream PRs from this batch — a stochastic re-run on PR #2 (auth / server routes) found additional security observations on the SQLite vs Postgres auth divergence (Postgres path still uses unsalted SHA-256 for API key storage vs the SQLite path's salted scrypt under PR #2541). The maintainer is best positioned to decide whether to backport #2541 to the Postgres rail.

---

Methodology note — pipeline self-improvement during this review

This review surfaced four bugs in the AntFleet pipeline before producing the findings above. All four shipped during the review:

  • GPT-5 chat-completions broken since the max_tokensmax_completion_tokens rename (AntFleet/antfleet#90)
  • GPT-5 token budget too low for reasoning + structured output (AntFleet/antfleet#91)
  • Consensus matcher dropped findings when one model returned path-only evidence (AntFleet/antfleet#91)
  • db.transaction() failing on the neon-http driver, silently breaking comment posting across all reviews (AntFleet/antfleet#92)

Evidence