OceanAltOceanAlt
latest2026-07-167 min read

Attack Lab #2: We Broke Our Own Firewall — A Thousand Small Payments

A per-transaction cap stops greed, not patience. We found our own reference implementation didn't satisfy our own standard (RAP Pillar 2), added a sixth gate, and caught an uglier float bug that killed legitimate payments. All real run data.

OOceanAlt Editorial

Attack Lab · Episode 2. This time the target was us — and we got through.

In Episode 1 we attacked our own compliance gateway six ways and every shot was blocked. The conclusion was "the line holds." This episode, we went looking for one it wouldn't hold.

We found it.

The hole: a thousand small payments

Our firewall has a per-transaction limit gate — any payment above the cap dies on the spot. So draining the wallet in one shot is impossible.

But a hijacked agent doesn't have to be greedy. It can spend 0.01 at a time, a thousand times.

Every single payment is under the cap. Every single one is perfectly "compliant." And the wallet is empty.

Our mandate at the time looked like this:

Per-transaction cap:  0.1 USDC   ✅ had it
Daily cumulative cap: —           ❌ didn't

RAP Pillar 2 says, in writing, "per-transaction / daily / cumulative limits." We had implemented only the first. Our own reference implementation did not satisfy our own standard. Not a good look — and true.

The patch: a sixth gate

We added a daily-cumulative gate: every agent's total spend for the day is accounted for, and once it exceeds the daily cap the payment dies — even if each individual payment is under the per-tx limit.

After patching, we ran a real test against the live gateway (per-tx cap 0.1, daily cap 0.3):

| Attempt | Amount | Result | |---|---|---| | #1 | 0.1 USDC | ✅ 200 allowed (cumulative 0.1) | | #2 | 0.1 USDC | ✅ 200 allowed (cumulative 0.2) | | #3 | 0.1 USDC | ✅ 200 allowed (cumulative 0.3, exactly at cap) | | #4 | 0.1 USDC | 🛑 403 blocked at the daily-cumulative gate |

Every payment was under the per-tx cap. #4 died anyway. The thousand-small-payments road is now closed.

Bonus: an uglier bug

On the first test after patching, payment #3 was blocked — but it should have passed (cumulative landing exactly on the cap).

The cause was this line:

if (spent + amt > dailyCap)   // spent=0.2, amt=0.1, cap=0.3

In IEEE 754, 0.2 + 0.1 = 0.30000000000000004, which is greater than 0.3. A perfectly legitimate payment was killed.

Never compare money as floats. We moved to integer micro-units (USDC's 6 decimals):

const micro = (x) => Math.round(x * 1e6);
if (micro(spent) + micro(amt) > micro(dailyCap))

Re-tested: #3 correctly passes, #4 correctly dies.

A gate that fails to stop bad payments is dangerous. A gate that kills good payments is dangerous too — it makes people turn the firewall off.

Three things this episode taught us

1. Defenses must be built per attack surface, not per intuition. A per-tx cap stops greed; it does not stop patience. Velocity and cumulative caps stop patience. Real attackers use both.

2. Measure your own implementation against your own standard. We wrote that RAP Pillar 2 requires per-tx/daily/cumulative — and shipped only per-tx. A standard isn't something you publish; it's something you're held to — so we're publishing the gap rather than quietly patching it.

3. In financial code, floats are the enemy. This bug hurts you with no attacker present.

Next episode

We're going after attribution: can one agent impersonate another, already-attributed agent? Bring your attack ideas.

Attack it yourself: oceanalt.com/firewall · Test with your own agent: integration guide

(OceanAlt Attack Lab · research note)

Provenance & status

Byline
OceanAlt Editorial
First published
2026-07-16
Last updated
2026-08-01
Source material
Source not labeled

Cite this piece

OceanAlt Editorial (2026). "Attack Lab #2: We Broke Our Own Firewall — A Thousand Small Payments". OceanAlt. https://oceanalt.com/en/articles/attack-lab-2-thousand-small-payments (accessed 2026-08-03)

This piece follows our editorial and fact-checking standards. Found an error? tell us — once verified, the correction will be published right here.