PropFlow Compliance Audit

The Instagram "10 ways your vibecoded app is getting sued" checklist, run for real against our repo, our live site, and our AWS account. Six parallel investigation agents, evidence at file-and-line level. 2026-08-13.

4Clean ✅
4Partial gaps ⚠️
2Real gaps ❌
1Prod bug found (billing portal 403)

Scorecard

#Claim from the reelVerdictOne-line reality
1No privacy policy✅ CleanLive at /privacy, footer-linked, sitemap'd, updated 2026-05-07
2No "we collect data" disclosure✅ Clean§2 enumerates contact, SMS/call, usage, IP — CCPA-specific wording could be tighter
3No AI mention in privacy policy✅ CleanClara, Anthropic + ElevenLabs named; no ADMT section yet (regs phase in through 2027)
4No third-party processors listed⚠️ Partial3 of ~9 named; AppFolio, AWS, Stripe missing; promised subprocessor list never published
5Not deleting user uploads❌ GapWe publicly promise "tenancy + 12 months" retention and deletion-on-request — neither is enforced by anything
6Storage bucket = public✅ CleanAll 8 buckets + account-level block verified; anonymous probe → 403; everything presigned
7Fake testimonials⚠️ PartialSite deliberately has zero testimonials (exemplary) — but blog posts claim production data we can't back
8Cancelling harder than signup❌ GapSelf-serve cancel path EXISTS but a wrong auth gate 403s real customers — the button silently does nothing
9Auto-renew without reminder⚠️ PartialMonthly B2B = low legal risk, but no reminder exists and the Terms have zero billing language
10AI with no self-harm response⚠️ PartialLikely outside SB 243 (customer-service exclusion) — but Clara has zero crisis handling today
In plain terms

The scary Instagram number was fake, but the exercise was worth it: we found one actual production bug (paying customers cannot cancel online — the button fails silently), one promise our privacy policy makes that our code doesn't keep (deleting old data), and one blog post claiming results from customers we don't have. Everything else is in better shape than most.

Item-by-item findings

1–4 · Privacy policy (CalOPPA / CCPA / CPRA)

What's right: propflowai.co/privacy is live, conspicuous, current (eff. 2025-03-01, upd. 2026-05-07), and matches the repo exactly. §2 discloses collection (contact info, SMS + call content and metadata, usage, IP, visit logs). §1 and §6 disclose Clara, Anthropic, ElevenLabs and Twilio by name. §6 states we don't sell personal information. §7 states retention windows. Terms §5 discloses AI-generated content limits.

Gaps:

5 · Data deletion & retention — the sharpest gap

The problem isn't that we lack a mechanism. It's that we publish promises no code enforces:

What IS enforced: visit logs really do delete after 90 days (TTL + purge script) — the one published claim with a mechanism behind it.

In plain terms

Our privacy page tells tenants "we delete your stuff after you move out, and sooner if you ask." Right now neither is true — nothing in the system ever deletes a photo, a conversation, or a call recording. A written promise you don't keep is worse than no promise: it's the first exhibit in a complaint.

6 · Storage buckets — fully clean, verified on the wire

All 8 buckets in account 194925971150 have the full four-flag Public Access Block, AND the account-level block is on — so even a future misconfigured bucket policy can't open public access. Anonymous probe of propflow-photos → HTTP 403 (verified live, not just config). Every photo serve path is auth-gated + presigned (1h expiry); a test explicitly pins that no signed URL leaks to the client. Zero public object URLs in product code. Nothing to fix.

7 · Testimonials — clean site, risky blog

The site's posture is exemplary — testimonials and case studies were consciously withheld until we have real, consented, attributed customers, and that policy is written into the code and the live case-studies page ("We'd rather ship one real case study than four anonymized ones").

The exposure is confined to blog editorial (src/app/(public)/blog/posts.ts, live at /blog/*):

Mockup personas (Sarah Martinez / Mike Torres) are fine — product-UI demos, never quoted as customers — though a small "simulated conversation" caption would harden them. NOI ranges on the marketing pages are properly labeled estimates with disclosed assumptions.

8 · Cancellation — a real bug, ~5-line fix

Designed right, broken in prod. Signup: self-serve Stripe Checkout from /settings ($10/unit/mo, recurring amount disclosed at consent). Cancel: a "Manage Subscription" button on the same page opens the Stripe Billing Portal — on paper, exactly as easy as signup.

But POST /api/billing/portal is gated by requireAdmin, which in production only accepts PropFlow staff. A paying customer clicking "Manage Subscription" gets a 403 — and the client only acts on data.url, so the button silently does nothing. Effective cancel path today: email us. That's the exact ROSCA "harder to cancel than sign up" shape. Undetected because our live relationships are hand-managed.

Secondary: the route trusts a client-supplied customerId — must be resolved server-side when the gate is fixed, or any user could open another customer's portal.

Fix: swap requireAdminrequireUser, resolve the Stripe customer from the caller's email server-side, surface non-OK responses in the client. Also verify the Stripe Dashboard portal config has cancellation enabled.

9 · Auto-renewal — low risk, zero-cost hardening

Monthly B2B billing = the low-risk quadrant (CA ARL is consumer-scoped and bites on annual terms; the FTC click-to-cancel rule was vacated July 2025, ROSCA baseline still applies). Settings shows the renewal date; checkout discloses the recurring amount. Gaps: no pre-renewal reminder anywhere (no invoice.upcoming handler), and the Terms page has zero mention of subscription, billing, fees, auto-renewal, or cancellation — the recurring charge has no contractual disclosure outside the Stripe Checkout screen. If an annual plan ever ships, a 15–45-day reminder becomes mandatory before launch.

10 · AI self-harm response (SB 243)

Legal scope: likely OUT — SB 243 targets companion chatbots "meeting a user's social needs" (Replika/Character.AI class) and carves out customer-service bots, which is squarely what Clara is. But the private right of action ($1,000/violation) means plaintiffs, not regulators, test that exclusion — and "anthropomorphic named persona + months-long tenant threads + collections conversations" is the fact pattern a complaint would lead with. Worth a one-time counsel confirmation in writing.

Factual finding: Clara has zero crisis/self-harm handling. Repo-wide grep for self-harm / suicide / crisis / 988 / hotline: no hits. What exists is physical life-safety only (gas, fire, "anyone hurt or trapped" → 911 + escalate), which is genuinely good — but a tenant texting "I can't take this anymore" mid-collections gets whatever the base model improvises, unmeasured, on a channel where the escalation email may not be read until morning. No eval case simulates it.

Recommendation (independent of legal scope): a crisis playbook is ~a day of work — prompt block (recognize ideation → share 988 → escalate_to_human high urgency → stop the business flow) + adversarial eval cases (SMS + voice, including a mid-collections shape).

Priority fix list

P0 — this week

P1 — this month

P2 — opportunistic

Method + receipts

Six parallel investigation agents: (1) privacy pages — repo + live-site fetch, verified identical; (2) deletion — repo grep + live DDB TTL check + live S3 lifecycle read; (3) buckets — live AWS CLI reads on all 8 buckets + account PAB + anonymous wire probe; (4) testimonials — repo + live pages + brand-assets repo; (5) billing — full route + client-path trace; (6) Clara — repo-wide crisis-term grep + prompt/eval inventory. File:line evidence embedded above. Legal baselines: CalOPPA $2,500/violation; CCPA/CPRA $2,500–$7,500 (AG/CPPA enforced) + $100–$750/consumer breach private right; FTC Reviews Rule $53,088/violation; ROSCA; CA ARL; SB 243 $1,000/violation private right (companion chatbots, eff. 2026-01-01).

PropFlow Docs