All documents · 08 Risk Legal

Loopcard — risk, legal, and ops challenge

Date: 18 September 2026
Role: adversarial risk / legal / ops (not counsel).
Product: Loopcard on https://cryptobook.space (preview). Code: /root/cryptobook-next/loopcard/.
This is not legal advice. Counsel reviews Terms, Privacy, AUP, and any public claim before paid launch or a new domain. Do not invent a US entity in the footer. VPS is in Germany.

Raw inputs: docs/08-legal-posture.md, docs/09-operations.md, challenges/legal.md, challenges/security.md. Product facts checked against loopcard/server.js, loopcard/cli/loopcard.js, loopcard/public/js/app.js, loopcard/lib/parse.js, and nginx cryptobook.conf.


0. What we actually ship (so the challenge is about this, not Slip)

Piece Fact
Parse Browser FileReader or local CLI. No multipart upload. Express JSON body 64 kb.
Publish POST /v1/cards stores amount, source (32), loop (280), kind (40), optional note (280), format, row_count, demo.
Share Unauthenticated GET /c/:id + /c/:id.png. public_id = lc_ + 10 hex chars (5 random bytes ≈ 40 bits).
PNG Homepage canvas download is local. Share PNG is server-side PIL spawn to /tmp.
Keys No OAuth. No vendor login. No LLM keys. No Stripe at launch.
Process PM2 name loopcard, one fork, 127.0.0.1:3100. nginx TLS on cryptobook.space. Postgres DB loopcard.
Rate App-wide express-rate-limit 120/min/IP. nginx limit_req 100 r/s (legacy social zone), limit_conn 20.

If a later feature logs into Anthropic/Cursor, holds API keys, scores people, or claims we cap spend, this document is void — that is a different product and a kill.


1. CFAA — we must not scrape vendor accounts

Kill line. Do not log into Anthropic, Cursor, OpenAI, GitHub, or any third party for the user. Do not scrape password-protected consoles. Do not call vendor APIs from 173.249.19.205 with stored user secrets. CSV/JSONL the user already exported, or labeled demo data. That is the BRIEF constraint and it is still the right one.

Why the Ninth Circuit does not give us a free pass. Amazon.com Services, LLC v. Perplexity AI, Inc., No. 26-1444 (9th Cir. Aug. 4, 2026) (Smith, J.; Tung, J.; Hinderaker, D.J., sitting by designation). Official PDF: cdn.ca9.uscourts.gov/datastore/opinions/2026/08/04/26-1444.pdf. Coverage still circulating mid-September: Cooley, 6 Aug 2026; Jones Day / Mondaq, 16 Sep 2026. Amazon asked the full court to rehear (Law360, 19 Aug 2026). The panel vacated a CFAA/CDAFA preliminary injunction because, on that record, Perplexity’s servers did not talk to Amazon; the user’s browser did. “However advanced the Assistant currently is, it is a tool, not a person for statutory purposes.” “It is the user who ‘accesses’ Amazon’s computers, with the help of the Assistant.”

The opinion says, at unusual length, what it is not doing: no new legal regime for agentic AI; no ruling on tort, ToS, copyright, or DMCA; facts with vendor-to-site TCP, more vendor control, or stored credentials used from the vendor’s network are left open. Distinguished from Facebook v. Power Ventures, 844 F.3d 1058 (9th Cir. 2016), where the defendant’s own systems caused messages on Facebook.

Loopcard today is on the safe side of that line only because we never enter the vendor computer:

Drift that re-opens CFAA (instant KILL):

  1. “Paste sk-ant-… and we pull your invoice.”
  2. Hosted browser / Computer-Use that opens console.anthropic.com from this VPS.
  3. A cron that scrapes vendor HTML with a session cookie we stored.
  4. Marketing that we “sync your Anthropic bill.”

ToS, copyright, and tort survived Perplexity. Even a clean CFAA posture does not license ignoring vendor terms if we fetch. User-initiated export is the architecture; keep it.

Residual. A user who exports a coworker’s workspace CSV and publishes it is the actor under Perplexity. We still host the URL. That is §2, not CFAA against us — unless we built the scrape.


2. Publish URLs — other people’s bills, defamation, employment

/c/:id is public, unauthenticated, crawled (OG title is $AMOUNT on SOURCE). Anyone with the link sees amount, caption, source label. The PNG is cacheable 24 h. There is no account, no report button, no takedown mailbox on the page, and legal@cryptobook.space is documented as “after it exists.”

Abuse Why it is real on this product Why it is not an automatic KILL
Posting a teammate’s bill Manual fields + CSV drop have no “is this yours?” check. A lead can mugshot an IC’s overnight. UGC; we did not create the number. Still a hosting/AUP problem.
Defamation Manual amount + loop can name a person or a shop (“Acme burned $80k, fired the intern”). False bill + share URL is a statement we serve. We do not assert the number is true; footer says “not an invoice.” That is not immunity.
Employment / performance A public $6,000 card used in a PIP, a hiring packet, or a “who wastes tokens” ranking. Annex III pt 4 and CA ADMT (opt-out 1 Jan 2027) attach to intended purpose. Ours is a screenshot, not a score. If we add leaderboards, badges, or “hire-worthiness,” it flips. Do not rank people. ToS: not a consumer report.
Doxxing via caption loop/note are free text, 280 chars, HTML-escaped on the page, not escaped out of existence on OG/Twitter. Length cap only.

Mitigations (keep / cheap).

Won’t fix (accepted). We will not KYC publishers. We will not watermark every PNG with a legal name. 40-bit IDs are unguessable enough for v1 obscurity, not a capability. Guessing is ~1e12; brute force of /c/ will 404, but a leaked URL is forever until we hide it.


3. Demo $6k — misrepresentation if unlabeled

The growth unit is a PNG of ~$6,000 / $1,263 / $480. Those are labeled re-creations of published 2026 reporting (Claude Code overnight; public Cursor-month; 30-team median). They are not access to anyone’s account and not our invoice.

Where the label actually is:

Surface Labeled?
Homepage trust line Yes: “Demos are labeled re-creations…”
On-page note / Origin Yes: Demo + “Published 2026 reporting”
/legal, /docs Yes
Share page {{NOTE}} if demo=true was published Yes, if they did not overwrite the note
Downloaded PNG (drawPng in public/js/app.js) No. Amount, source, loop, kind, “virtus labs.” No “DEMO,” no “re-creation.”
Server PNG (lib/render_card.py) No. Same fields. demo is in Postgres and never drawn.
Homepage og:description “Someone’s Claude Code ran overnight. About $6,000. Here’s the card. Make yours.” — story-shaped, not a disclaimer.

FTC § 5 cares about net impression, not the footer. An unlabeled $6,000 CLAUDE CODE card on X reads as a live invoice. If we, or a contractor, post that PNG without “re-creation / not a private invoice,” that is our misrepresentation. If a user republishes the demo as “my bill,” that is theirs — we still supplied the default.

Mitigations.

Won’t fix. We will not watermark user-export PNGs with “estimate” unless the parser path is JSONL list-rate (those totals are estimates: Sonnet $2/$10, Opus $5/$25, Haiku $1/$5 per MTok, Sep 2026). JSONL estimate vs vendor invoice mismatch is a support and FTC-substantiation issue if we call it “your bill” without “estimated.” Docs already say estimates. PNG still shows a hard dollar. Residual: keep the word estimated in JSONL loop headlines (parser already does).


4. GDPR / EU, 18+, US

Intended picture (docs/08-legal-posture.md): US-facing, 18+, honor-system “not from EU/EEA/UK” in v1, geo-block later if still required. No children’s product. No Annex III purpose (not hiring, credit, education admissions, health, LE, justice).

What is live: a trust line “US-oriented · 18+ · not legal advice.” No checkbox. No age gate. No geo-block. nginx does not distinguish Union IPs. The box is a German Contabo VPS (vmi3003269, 173.249.19.205). Processing in the EU of EU visitors’ IPs is a GDPR facts pattern even if copy says US-oriented.

Data Where GDPR-ish?
nginx IP / UA /var/log/nginx/cryptobook.access.log Yes, personal data if it identifies a person. Ordinary logs. No documented retention.
Theme localStorage key cryptobook:themeMode Not a cookie; still disclose.
Published card Postgres cards — amount + caption, public URL If the caption names a person, or the amount is reasonably identifiable with a handle, that is personal data we host and send to crawlers.
File bytes Not on server (confirmed) N/A for GDPR storage; local parse is the user’s device.
Accounts / email None in v1 Good. Do not add EU accounts without a real privacy program.

EU AI Act. Intended purpose is a shareable bill PNG, not Annex III. Article 50 transparency (in force 2 Aug 2026) is about AI that interacts with people or marks synthetic media. Loopcard is not a chatbot; the demo is a static re-creation. Do not CE-mark, do not sell “AI Act compliant.” High-risk Annex III standalone duties deferred toward Dec 2027 by the 2026 Digital Omnibus — not a free pass to build employment scoring.

Children. COPPA Rule amendments: compliance deadline 22 Apr 2026. California 2026 kids/chatbot bills (AB 2246, SB 1119, etc.). A public playground with no age gate is the trap. Loopcard is not child-directed if we do not market to schools. Honor-system 18+ is weak. Do not add classroom SKUs.

US state privacy / ADMT. We do not make “significant decisions” about people. Users might. ToS prohibition + no scores. CCPA “business” thresholds are operational if we grow; no sale of personal information.

Mitigations.

Won’t fix. No verifiable age. No Schrems paper. No DPO. No DSAR portal. No cookie banner for theme localStorage. We will not pretend GDPR “compliant.” US-oriented is a market posture, not a legal opinion that EU law cannot apply.


5. Credential / CSV secrets — we do not upload files (residual)

Confirm: the file is not posted.

Residual risk if someone hits Publish “wrongly”:

  1. Secrets in the fields we do store. source is sliced from a CSV model/product column (24 chars in parser, 32 on the server). If that column is actually a key, token, email, or internal project name, Publish puts it on a public URL and in a PNG. Parser does not strip sk-, sk-ant-, Bearer, ghp_.
  2. Manual caption. User can type a password or a customer name into loop / note. Publish sends it. That is user error; we still host it.
  3. CLI walk of ~/.claude/projects. JSONL often contains prompt bodies. The parser only sums usage tokens and builds a headline from totals — it does not currently copy prompt text into loop. A parser bug, a “helpful” dump of message.content, or a future --upload-bodies would become a prompt lake. Security challenge: do not implement --upload-bodies in v1.
  4. Wrong file, right click. User drops .env or a key CSV. Parse may fail (good) or may sum a numeric column and publish a nonsense amount with a leaked source. No client-side secret scan.
  5. nginx client_max_body_size 100M is leftover from social video. App JSON is 64 kb, so a 100 MB POST dies in Node, not nginx. Residual: a mistaken proxy or a future upload route would inherit 100 MB. Lower it for /v1/ when ops touches the vhost.
  6. Debug logs. console.error(e) on save/render. Do not log req.body in full. Architecture (refuse file bytes) is the control; logging config is not.

Mitigations.

Won’t fix. We will not run a DLP product on 280-character captions. We will not hold keys “encrypted at rest” — that was the security kill for the gateway. Local JSONL with prompts stays on the user’s disk; we cannot un-read it.


6. Brand — CryptoBook leftover, expired-cert history

Fact Risk
Preview host is cryptobook.space Crypto-social leftover. ~65 unique IPs and ~1,500 nginx hits in 7 days to 18 Sep 2026, mostly old social APIs. Conversion tax, not a PLG channel. H1 is Loopcard (good). Do not put CryptoBook in the H1.
cryptobook.com A = 217.160.223.94 (IONOS Apache) Not us. Advertising .com from this VPS is false until DNS changes.
TLS outage Let’s Encrypt for cryptobook.space expired 2026-04-11. Not an app outage; certbot/webroot. Renewed 18 Sep 2026; leaf until 2026-12-17. Academy had the same class of failure (expired 2026-04-19). Catch-all location ~ /\. without ACME exclude will break HTTP-01 again.
Theme key cryptobook:themeMode Harmless leftover; still says CryptoBook in DevTools.
CSP on the vhost Still allows Google/Facebook script origins from the social app. Unused by Loopcard. Residual XSS surface + mixed-product story.
Footer / legal Virtus Blockchain Labs. Do not invent Delaware.

Mitigations. Buy loopcard.ai / .app / getloopcard.com and move the A record. Keep ACME location ^~ /.well-known/acme-challenge/ on port 80 before return 301, and on 443 before hidden-file deny. certbot renew --no-random-sleep-on-renew for interactive work. Calendar the 17 Dec 2026 expiry. Strip social CSP when ops can do it without breaking a leftover /rtc if LiveKit stays.

Won’t fix. We will not litigate the word “CryptoBook” off old indexes this month. Expired-cert history is already in the public Web. A new name is the fix; a blog post is not.


7. Ops — VPS, nginx, PM2, single process

Box. vmi3003269, Ubuntu 24.04, 173.249.19.205, Germany. Apps historically run as root via PM2. SSH: PermitRootLogin yes, password auth, empty authorized_keys, no fail2ban (operator policy: do not lock out root-password sessions in this ticket). Postgres/Redis/Mongo localhost. No HSM, no tenant KMS, no SOC 2. Assume attacker gets root or the Node app (challenges/security.md).

Loopcard process. ecosystem.config.cjs: instances: 1, exec_mode: fork, bind 127.0.0.1:3100. One Node event loop. PNG render spawns python3 lib/render_card.py per /c/:id.png, writes /tmp/lc_*.png, unlinks on stream close. A hung Python or a /tmp fill is an outage for all cards, healthz, and static-via-Node.

nginx. Public 80/443 only. /v1/ and /c/ and /healthz proxy to loopcard. Static root /var/www/loopcard. Old social still in the same vhost (cryptobook_backend :3000, LiveKit /rtc /twirp). TURN 3478 and RTC UDP 50000–60000 remain open for the retired video product. Do not open 3100 on WAN.

Single-process residuals (won’t fully fix on this VPS):

Mitigations. Keep bind localhost. Keep JSON 64 kb. Cap concurrent PIL spawns (not implemented — gap). PM2 max_restarts. Do not put LLM keys on this machine. Do not reuse LiveKit for Loopcard. When touching nginx: never deny ACME; lower client_max_body_size on /v1/. Health: curl -sS https://cryptobook.space/healthz.

Won’t fix. No second region. No SOC 2. No non-root PM2 in this document’s scope. No “100% secure.” SSH/UFW hardening is a separate operator ticket (keys, then disable passwords, fail2ban). This product must stay boring enough that a VPS breach is a bad week (public amounts + IPs), not “we drained 4,000 Anthropic keys.”


8. Abuse of POST /v1/cards (spam PNGs)

Unauthenticated publish is the growth mechanic. It is also a free image CDN and a graffiti wall.

Vector Mechanics Harm
Card spam 120 JSON POSTs/min/IP → 120 public URLs Noise, defamation mill, SEO junk on /c/lc_*
PNG DoS Each GET /c/:id.png spawns Python + PIL 1080² CPU, /tmp, PM2 stall. nginx conn limit 20 helps; Express limiter is shared with POST (120/min) and is not spawn-aware.
Cache Cache-Control: public, max-age=86400 on PNG Good for us; also good for a viral defamatory card.
Huge amounts Server allows 0 … 1e9 $1,000,000,000 meme cards. Harmless except brand.
Bot flood No captcha, no API key Scriptable. Social crawlers are allowed in $bad_bot (needed for OG).

Mitigations.

Won’t fix. No Cloudflare WAF in this stack. No account-to-publish requirement at $0 launch (that would kill the 60-second path). Captcha can wait until we see actual flood. 40-bit IDs stay.


9. Insurance — we are not a cost-cap; users may think we are

Homepage “What this is not”: Not a cost cap. “Your vendor still stops the runaway. We show the tab.” Docs/FAQ: Cursor spend limits and Claude usage caps stop the loop; we will not claim we stop it. Community playbook already has the objection reply.

Why users will still get it wrong.

Mitigations. Keep the “not a cost cap” tile. /legal: not an invoice, not insurance, not a spend limiter. Support macro: “Set the cap in Cursor/Claude. Then screenshot.” Never sell “we would have saved you $6k.” Never add a kill-switch we do not have.

Won’t fix. We cannot stop a buyer from believing a pink card is coverage. We will not buy E&O / cyber that treats us as a cost-control product — we are not one. If copy drifts to “stop the loop,” that is an FTC problem and a product lie.


10. Scoreboard

Topic Verdict One-line
CFAA / vendor scrape SURVIVE if we never log in Perplexity is user-not-developer on user-browser facts. Hosted scrape = KILL
Publish URLs / defamation / others’ bills FIX Public UGC; need confirm + hide; no people-ranking
Demo $6k unlabeled PNG FIX Page is labeled; PNG is not. Draw DEMO on demo renders
GDPR / EU / 18+ / US FIX (operational) Honor-system only; German VPS; no geo-block. Not Annex III by purpose
File upload / secrets SURVIVE with residual Files not uploaded (confirmed). Caption/source can still leak
Brand / expired cert FIX New domain; ACME hygiene; Dec 2026 expiry
Ops single process Accept One PM2 fork on a shared VPS. Isolation is “don’t hold keys”
/v1/cards spam PNGs FIX Tighter POST/PNG limits + spawn cap
Insurance / cost-cap confusion FIX copy We show the tab. Vendors cap. Not coverage

Kill if we add: vendor OAuth or Admin API; key custody; prepaid LLM credits; tokens; employment/credit scores; kids/classroom; “SOC 2 / AI Act / we cap your spend / we are your insurance”; server-side file ingest.


11. Mitigations vs residual “won’t fix”

Do (cheap, product law)

  1. Never scrape or OAuth into vendor billing. Export-in-browser only.
  2. Stamp DEMO · re-creation on demo PNGs (canvas + PIL).
  3. Publish confirm: public URL, my bill, 18+, not EU (honor-system).
  4. Secret regex on source/loop/note; keep 64 kb JSON; no multipart.
  5. Stricter rate limit on POST /v1/cards and PNG render; cap concurrent Python.
  6. hidden_at (or delete) for takedown; mailbox you read.
  7. Keep “not a cost cap / not an invoice / not legal advice / not a certification” on /, /legal, /docs.
  8. ACME exclude + calendar cert expiry; do not advertise cryptobook.com.
  9. JSONL headlines stay estimated. Do not call them invoices.
  10. No gallery, no people leaderboard, no --upload-bodies.

Won’t fix (accepted residual)


12. Counsel checklist (not done)

Nothing here is a statement that Loopcard is “compliant.” It is a challenger’s map of landmines, the patches that keep the current architecture off the kill list, and the residuals we are choosing not to close on a $0, 1-VPS preview.

Not legal advice. Sources fetched or re-checked 18 September 2026: 9th Cir. 26-1444 (4 Aug 2026); Cooley 6 Aug 2026; Jones Day/Mondaq 16 Sep 2026; product and nginx as deployed that day.