Cross-cutting · verified · PII coverage by service

PII Firewall Boundary Map

Which services actually screen user-supplied text for PII before acting on it — and which ones don't?

Last verified 2026-04-17 against code
Slug pii-boundary-map
Classifier Bedrock (via moderation_core.pii_firewall)
Semantics fail-closed

§1 What this answers

COPPA compliance requires that PII from under-13 users not reach downstream vendors (LLMs, image generators, sound generators, etc.) without parental consent. The PII firewall is the code-level gate. This diagram shows, for every user-facing service, whether that gate is wired in and where.

Shared classifier, per-service wrappers. One classifier lives in moderation_core/pii_firewall/ (Bedrock-backed, 2184-line executor.py). Each service decides independently whether to call it and when. That's why the coverage is uneven.

§2 Coverage by service

FuzzyCode ON

Wrapperquart_server/services/pii_firewall.py
GatesAI route prompts · HTML cleanliness · publish attestation
Semanticsfail-closed
Evidencepii_firewall.py:40-106

SoundBuddy ON

WrapperSoundBuddyFastAPI2/pii_firewall.py
Gates/sound · /sound_effect · /music prompts
Semanticsfail-closed
Evidencepii_firewall.py:1-136

ImageBuddy ON

WrapperImageBuddyRobustFastAPI/pii_firewall.py
GatesAI-generation prompts
Semanticsfail-closed
Evidencepii_firewall.py:1-288

SpriteBuddy ON

WrapperSpriteBuddy/pii_firewall.py
Gatesmotion prompts · /proxy_video_ai
Semanticsfail-closed
EvidenceSpriteBuddy/pii_firewall.py

UploaderBuddy NONE

Wrapper— missing —
PII surfacefilenames · EXIF · embedded text in images
Riskchild uploads bypass any PII check
Evidencegrep -l pii_firewall UploaderBuddy/ → 0

Pages NO FIREWALL

WhyRelies on FuzzyCode's HMAC attestation that content was scanned upstream
Riskany non-browser-ordinated write path would bypass PII screening
Evidencemain.py:2202-2234 verifies attestation · no firewall call

SimpleGPT ADMIN-ONLY

StatusNot user-facing; admin JWT + service-key gated
PII firewallnot wired (by design per PII_FIREWALL doc line 278)
Evidencesimplegpt-fastapi/main2.py:158-280

ModerationBuddy N/A

Purposecontent moderation, not PII
NoteNo user-facing callers; see moderation-pipeline diagram

CDNBuddy · S3BucketBuddy N/A

Purposeinfra helpers; no user text input

§3 Where the gate runs

The gate sits between "user submits text" and "any vendor call or persistence." Fail-closed semantics: on ambiguous result or error, the firewall raises — the handler must translate to a 400/503 to the user, never proceed silently.

flowchart LR classDef user fill:#fff460,stroke:#683c06,color:#111 classDef gate fill:#fdecea,stroke:#b8432e,color:#111 classDef ok fill:#e8f6ec,stroke:#2f7a3e,color:#111 classDef ext fill:#c7d9e8,stroke:#1d58b1,color:#111 classDef bypass fill:#eaeaec,stroke:#6b6455,color:#555,stroke-dasharray: 4 3 U([user prompt]):::user U --> AGE{age ≥ 13
and mode=under13_only?} AGE -->|yes| SKIP[skip firewall]:::bypass AGE -->|no / mode=all| SCAN[PII firewall
Bedrock classifier]:::gate SCAN -->|result=clean| OK[proceed to vendor]:::ok SCAN -->|result=PII detected| X1[400 · pii_detected]:::gate SCAN -->|result=ambiguous| X2[403 · pii_approval_required]:::gate SCAN -->|error / unavailable| X3[503 · pii_firewall_error]:::gate OK --> Vendor[OpenAI / FAL / ElevenLabs / Groq / Bedrock]:::ext SKIP --> Vendor style AGE fill:#fff4d6,stroke:#a47a3a,color:#111

§4 Feature flags

Env varDefaultEffectEvidence
PII_FIREWALL_MODE"all"all scans every prompt; under13_only skips for users 13+; off disables the gate entirelyexecutor.py:56, 531-539
PII_FIREWALL_MODEL_IDopenai.gpt-oss-20b-1:0Bedrock model used for classificationexecutor.py:30
PII_FIREWALL_PROVIDER_MODEgroq (UAT)Provider selectordocker-compose.yml:45
PII_FIREWALL_LINE_ID_OUTPUT_MODEidonlyPrompt variantdocker-compose.yml:46
PII_FIREWALL_SPLIT_TARGET_LINES20Chunk large payloadsdocker-compose.yml:47
PAGES_CLEAN_ATTESTATION_SECRETrequiredHMAC secret for FuzzyCode → Pages publish attestationhtml_cleanliness.py:267-289
Single-point-of-control risk. Setting PII_FIREWALL_MODE=off disables the firewall everywhere with no service restart interlock. Any incident playbook touching this env var needs sign-off.

§5 The HTML path — a specialized PII flow

Beyond prompts, FuzzyCode also checks the HTML being published for PII leakage. The state of that check is persisted on the page row so Pages can verify it without re-scanning.

flowchart LR classDef step fill:#fdf6ea,stroke:#683c06,color:#111 classDef ok fill:#e8f6ec,stroke:#2f7a3e,color:#111 classDef fail fill:#fdecea,stroke:#b8432e,color:#111 E[Editor save] --> V[/api/html/verify-cleanliness
preflight/]:::step V --> S[PII firewall scan] S -->|clean| C1[persist html_clean_state=
verified_clean + hash]:::ok S -->|dirty| C2[persist html_clean_state=
dirty_unverified]:::fail C1 --> P[/api/pages/attest-publish/]:::step P --> H[HMAC-sign attestation
html_hash · clean_state · clean_basis · title_hash] H --> PS[Pages /submit]:::step PS --> VF[verify HMAC +
clean_state==verified_clean] VF -->|ok| STORE[INSERT / UPDATE page row]:::ok VF -->|mismatch| R400[400 attestation mismatch]:::fail

Three states in code (verified_clean · dirty_unverified · blocked), not the five-state machine described in PII_FIREWALL_SHARED_ARCHITECTURE.md's "Proposed" section. The two are often cited interchangeably — they shouldn't be.

§6 Verification pointers