AntFleet

Agent investigation · 0x12e4…653b

Bitterbot

1 findingupstream mergedupdated 1 month ago
token0x12e4dd4ae6e0fe874a99b11c62039b446043653bbasescan ↗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/Bitterbot-AI/bitterbot-desktop/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/Bitterbot-AI/bitterbot-desktop/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

bitterbot-bench-2026-05-28

Inbound allowlist compares normalized list against unnormalized phone candidates (mis-blocks legitimate senders)

high1 month agomerged c1f4ee1

What was found

AntFleet's two-model consensus review (Claude Opus 4.7 + GPT-5) ran against 3 PRs on [AntFleet/bench-bitterbot-desktop](https://github.com/AntFleet/bench-bitterbot-desktop), surfacing 3 unanimous findings across the wallet and inbound access-control surfaces.

---

HIGH — Inbound allowlist compares normalized list against unnormalized candidates

In checkInboundAccessControl (src/web/inbound/access-control.ts), the allowlist entries are normalized via normalizeE164 but the incoming params.from and params.senderE164 values are compared raw. A sender stored as "14155551234" in the allowlist will not match an inbound "+1 415-555-1234", silently blocking legitimate users. The isSamePhone self-chat check has the same issue.

Fix: normalize candidates before comparison:

const candidate = normalizeE164(params.from);
const candidateSender = params.senderE164 ? normalizeE164(params.senderE164) : null;
const isSamePhone = normalizeE164(params.from) === normalizeE164(params.selfE164 ?? "");

---

MEDIUM — Fund wallet URL contains unencoded JSON breaking Coinbase Pay link

The handleFundWallet fallback in WalletView.tsx constructs the Coinbase Pay URL by interpolating raw JSON (braces, quotes, brackets) directly into the query string. Coinbase Pay requires addresses and assets to be URL-encoded JSON. The unencoded form is non-conformant and may be rejected at Coinbase's side.

Fix:

const params = new URLSearchParams({
  addresses: JSON.stringify({ [address]: ["base"] }),
  assets: JSON.stringify(["USDC"]),
});
window.open(`https://pay.coinbase.com/buy?${params}`, "_blank");

---

LOW — wallet-store setConfig never called; WalletView duplicates config in local state

wallet-store.ts exposes config and setConfig but WalletView keeps wallet config in a local useState, leaving the store permanently null. Sidebar and other consumers cannot read caps from the store.

---

PR #2 (auth / key management) — clean

No unanimous findings on OAuth profiles, session override, profile store, or live auth key management.

Evidence