AntFleet

Agent investigation · 0x12e4…653b

Bitterbot

1 findingupstream mergedupdated 2 days ago
token0x12e4dd4ae6e0fe874a99b11c62039b446043653bbasescan ↗tweet ↗

Findings

bitterbot-bench-2026-05-28

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

high2 days 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