Overview
A refund-recovery service for small importers. In February 2026 the Supreme Court ruled that a class of tariffs imposed under the IEEPA emergency-powers statute had no legal authority, which opened a refund path on the duties already collected. Upload your customs entries, see what you're owed, and get connected to a licensed customs broker to file. All against protest deadlines that expire on a fixed legal schedule. 729 commits and 427 merged PRs in 29 active days.
Project Design
Scaffolded in a single ~40-commit day. Privacy was a day-one decision, not a retrofit: analytics and error tracking shipped with importer-data scrubbing already wired in. A federal customs regulation shaped the product. A compliance audit of the site's own wording found 18 violations, so the forbidden phrasings got wired into the build checks, where a violation can't ship past the pages the check covers. And mid-build, the evidence forced a pivot: from $79 self-serve filing to free analysis plus a broker connection.
Key modules
ES-003 parser
Parses ACE entry exports by header name and classifies IEEPA vs. Section 301/232 tariff lines.
Entry classifier
Runs an 8-category eligibility triage with CBP CAPE Stage-2 edge-case flags.
CAPE CSV generator
Produces CBP-compliant declaration CSVs — deduped, check-digit validated, grouped by importer.
Clerk ↔ RLS bridge
Bridges non-UUID Clerk IDs into row-level security and merges anonymous sessions on sign-in.
PII scrubbing
A four-layer denylist keeps entry numbers, HTS codes, and duty amounts out of analytics and error reports.
Lead scoring
Scores broker-match leads on refund size, deadline urgency, and complexity; disqualifies sub-threshold entries.
Key features
RAG chatbot — security checks in the code, not the prompt
The site's assistant is a retrieval-augmented chatbot — it answers from a fixed knowledge base of CBP guidance rather than the model's memory — and its defenses live in the request path, not just the system prompt. Every message runs a gauntlet before the model is called: input validation, a twelve-pattern prompt-injection scan that returns a 400, IP rate limiting, and a relevance gate where the retrieval step itself refuses anything that doesn't resemble the customs knowledge base. Underneath, row-level security and database grants revoked from the public roles mean a prompt talked into misbehaving still can't reach data it shouldn't. The signed-in version answers questions about a user's own analysis from aggregates, never raw entry rows.
Read: A prompt is not a perimeter →
Compliance-as-CI — honesty enforced in the build
A federal customs-broker regulation limits what an unlicensed tool may claim. Rather than rely on careful writing, TariffRefunded turned the rule into a build check: a denylist of forbidden phrasings ("we produce your CBP declaration," "these are good to go") is grepped on every change to the public marketing pages, and a match blocks the merge unless a reviewer justifies it inline. The first audit found 18 violations across the site; wiring the denylist into CI kept them from creeping back as the product pivoted. The honest caveat: the gate only covers the pages it's pointed at — a phrase outside that scope can still slip through, so the boundary definition is the real control.
Security & ops decisions
- Analytics autocapture was off from day one — manual instrumentation only — backed by a four-layer PII scrubber covering client, server, error reports, and breadcrumbs.
- The most reliable scrubber is not storing the data: full importer-of-record numbers were dropped from the schema entirely, replaced by a suffix key and an opaque group ID.
- A federal regulation's forbidden phrasings live in a pre-commit denylist gate, so a compliance violation can't ship.
- Anonymous sessions got real security design: header-bound row access, and a merge function that raises rather than letting an unauthenticated caller hijack an account merge.
Builder notes
- Scaffolded in a single ~40-commit day: auth, hardened analytics, error tracking with scrubbing wired in, and a tariff rate table covering 12 regimes.
- The in-repo pentest harness grew to 13 attack-category test modules plus scanner automation — and was later extracted and open-sourced as StackBadger.
- A versioned strategy doc with an open-decisions table, audited against the live site on dated passes, produced numbered P0–P2 findings traceable to fixing PRs.
- Clerk user IDs aren't UUIDs: replacing auth.uid() with the JWT subject claim in eight places became a hard project rule after every authenticated query failed.
Lessons learned
- A market can have an expiration date. The addressable refund pool shrinks an estimated 8–10% a month as protest windows close, and the strategy priced that decay in from day one.
- Regulatory compliance works best as an automated gate, not a style guide: the wording audit became a denylist in the build pipeline. But a gate is only as good as its scope — one forbidden phrase survived in a page the check didn't cover.
- A launch gate written in advance (no broker-match promise without a signed partner) is only worth what you'll sacrifice to honor it. It held.
- The pivot itself created new compliance violations: features kept promising a partner that didn't exist yet. Copy drifts toward whatever the feature wants to promise.
What carried forward
StackBadger was born here, as the internal pentest harness. So did three habits that moved into everything after: the PII-scrubbing patterns, the Clerk-to-RLS auth fix, and a decision-hygiene routine — a versioned strategy doc with an open-decisions table, plus dated audits that diffed the live site against it.
Posts from this project
A prompt is not a perimeter
My customs chatbot's system prompt politely asks attackers not to misbehave. That's the weakest control it has — the ones that actually hold are in the request path and the database.
The regulation in my build pipeline
A federal statute constrains what my product is allowed to say. An audit found 18 violations in my own copy — so I wired the forbidden phrasings into the build and made shipping one impossible.
Building for a market with an expiration date
A Supreme Court ruling created a multi-billion-dollar refund pool — one that shrinks every month on a fixed legal schedule. A decaying market changes every product decision.