Surfaced by the architecture review and narrowed by direct source verification — most of the review's "child-safety gaps" were refuted; this is the single genuine residual.
Safety controls that ALREADY exist (verified in code — for context, so this ticket stays scoped)
Prompt moderation on generation: IPromptModerationService.ModerateAsync(prompt) at SubmitArtAssetCommandHandler.cs:137 + RestartFromStageCommandHandler.cs:73, fail-closed (PromptModerationResult.Rejected).
Output image NSFW gate (#349): ArtifactSafetyGate — every AI-generated image is NSFW-checked before storage, enabled + fail-closed by default (ArtPipeConfig.cs:103).
GDPR erasure + portability: DeleteAccountCommand (cascade to child accounts + Keycloak user + student git repo) and ExportAccountDataQuery (data-export ZIP), ServiceCollectionExtensions.cs:614.
The gap
A student can upload a source image to the art pipeline (SubmitArtAssetCommand.SourceImageGridFsId). That upload is malware-scanned (ClamAV) and quarantined, and generated outputs are NSFW-gated — but there is no known-CSAM hash-matching on the uploaded image itself (searched: photodna|csam|thorn|hash-match → none). NSFW-classification ≠ CSAM detection: NSFW models score adult content probabilistically; CSAM detection is perceptual-hash matching against NCMEC/industry hash sets and is a distinct control.
Why it matters
A US platform that hosts imagery uploaded by/around minors has statutory obligations under 18 U.S.C. §2258A: on actual knowledge of apparent CSAM, report to NCMEC (CyberTipline) and preserve. Relying on an NSFW classifier neither reliably detects known CSAM nor satisfies the reporting duty.
Recommendation
Integrate a CSAM-detection service on the upload path — Microsoft PhotoDNA or Thorn Safer (perceptual-hash match against NCMEC hash sets), running in the UploadCoordinator/SecurityScanner flow before the image is usable, fail-closed like #349.
Add an NCMEC CyberTipline reporting pipeline + evidence-preservation + staff escalation for positive matches (this is an event-handler-shaped workstream: match → SecurityMonitor/incident → report + quarantine-hold).
Legal review of the retention/preservation obligations for flagged content.
Type: backend/security/compliance. Priority: high (legal + child-safety), but scoped — this is an additive control on top of an already-strong safety stack, not a rebuild. Relates to #349, #352, [#401].
Surfaced by the architecture review and **narrowed by direct source verification** — most of the review's "child-safety gaps" were refuted; this is the single genuine residual.
## Safety controls that ALREADY exist (verified in code — for context, so this ticket stays scoped)
- **Prompt moderation** on generation: `IPromptModerationService.ModerateAsync(prompt)` at `SubmitArtAssetCommandHandler.cs:137` + `RestartFromStageCommandHandler.cs:73`, fail-closed (`PromptModerationResult.Rejected`).
- **Output image NSFW gate (#349)**: `ArtifactSafetyGate` — every AI-generated image is NSFW-checked before storage, **enabled + fail-closed by default** (`ArtPipeConfig.cs:103`).
- **Upload malware scan**: `SecurityScanner` + **ClamAV** (`SecurityScanService.cs`), size caps, quarantine.
- **Gallery moderation** (#352): flagged-asset queue, staff review, quotas/usage meters.
- **GDPR erasure + portability**: `DeleteAccountCommand` (cascade to child accounts + Keycloak user + student git repo) and `ExportAccountDataQuery` (data-export ZIP), `ServiceCollectionExtensions.cs:614`.
## The gap
A student can upload a **source image** to the art pipeline (`SubmitArtAssetCommand.SourceImageGridFsId`). That upload is malware-scanned (ClamAV) and quarantined, and *generated* outputs are NSFW-gated — but there is **no known-CSAM hash-matching** on the uploaded image itself (searched: `photodna|csam|thorn|hash-match` → none). NSFW-classification ≠ CSAM detection: NSFW models score adult content probabilistically; CSAM detection is perceptual-hash matching against NCMEC/industry hash sets and is a distinct control.
## Why it matters
A US platform that hosts imagery uploaded by/around minors has statutory obligations under **18 U.S.C. §2258A**: on *actual knowledge* of apparent CSAM, report to **NCMEC** (CyberTipline) and preserve. Relying on an NSFW classifier neither reliably detects known CSAM nor satisfies the reporting duty.
## Recommendation
1. Integrate a CSAM-detection service on the upload path — **Microsoft PhotoDNA** or **Thorn Safer** (perceptual-hash match against NCMEC hash sets), running in the `UploadCoordinator`/`SecurityScanner` flow before the image is usable, fail-closed like #349.
2. Add an **NCMEC CyberTipline reporting** pipeline + evidence-preservation + staff escalation for positive matches (this is an event-handler-shaped workstream: match → `SecurityMonitor`/incident → report + quarantine-hold).
3. Legal review of the retention/preservation obligations for flagged content.
**Type:** backend/security/compliance. **Priority:** high (legal + child-safety), but **scoped** — this is an additive control on top of an already-strong safety stack, not a rebuild. Relates to #349, #352, [#401].
Verified 2026-08-07 against spikersoft-backend@98102023: not started.git grep -rniE "photodna|csam|ncmec|hash-match|cybertip" returns zero matches — no perceptual-hash matching on the upload path, no CyberTipline reporting pipeline. The adjacent controls this ticket deliberately scopes around are all still in place (prompt moderation, ArtifactSafetyGate, ClamAV SecurityScanner, gallery moderation, GDPR erasure/export), and live api.spikersoft.com/healthz shows the art.model.safetycheck.tasks queue running, so the new control would slot alongside an existing safety stage.
Status: not started. Worth flagging that the long pole is procurement — PhotoDNA/Thorn both need an account and a legal agreement before any handler can be written.
Closing here. Work now lives in the repo that holds the fix, so fixes #564 in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.
— Opus 5 Agent
Migrated to **spikerj/spikersoft-backend#564** as part of the umbrella-tracker breakup.
Verified 2026-08-07 against `spikersoft-backend@98102023`: **not started.** `git grep -rniE "photodna|csam|ncmec|hash-match|cybertip"` returns **zero matches** — no perceptual-hash matching on the upload path, no CyberTipline reporting pipeline. The adjacent controls this ticket deliberately scopes around are all still in place (prompt moderation, `ArtifactSafetyGate`, ClamAV `SecurityScanner`, gallery moderation, GDPR erasure/export), and live `api.spikersoft.com/healthz` shows the `art.model.safetycheck.tasks` queue running, so the new control would slot alongside an existing safety stage.
Status: not started. Worth flagging that the long pole is procurement — PhotoDNA/Thorn both need an account and a legal agreement before any handler can be written.
Closing here. Work now lives in the repo that holds the fix, so `fixes #564` in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.
— Opus 5 Agent
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Surfaced by the architecture review and narrowed by direct source verification — most of the review's "child-safety gaps" were refuted; this is the single genuine residual.
Safety controls that ALREADY exist (verified in code — for context, so this ticket stays scoped)
IPromptModerationService.ModerateAsync(prompt)atSubmitArtAssetCommandHandler.cs:137+RestartFromStageCommandHandler.cs:73, fail-closed (PromptModerationResult.Rejected).ArtifactSafetyGate— every AI-generated image is NSFW-checked before storage, enabled + fail-closed by default (ArtPipeConfig.cs:103).SecurityScanner+ ClamAV (SecurityScanService.cs), size caps, quarantine.DeleteAccountCommand(cascade to child accounts + Keycloak user + student git repo) andExportAccountDataQuery(data-export ZIP),ServiceCollectionExtensions.cs:614.The gap
A student can upload a source image to the art pipeline (
SubmitArtAssetCommand.SourceImageGridFsId). That upload is malware-scanned (ClamAV) and quarantined, and generated outputs are NSFW-gated — but there is no known-CSAM hash-matching on the uploaded image itself (searched:photodna|csam|thorn|hash-match→ none). NSFW-classification ≠ CSAM detection: NSFW models score adult content probabilistically; CSAM detection is perceptual-hash matching against NCMEC/industry hash sets and is a distinct control.Why it matters
A US platform that hosts imagery uploaded by/around minors has statutory obligations under 18 U.S.C. §2258A: on actual knowledge of apparent CSAM, report to NCMEC (CyberTipline) and preserve. Relying on an NSFW classifier neither reliably detects known CSAM nor satisfies the reporting duty.
Recommendation
UploadCoordinator/SecurityScannerflow before the image is usable, fail-closed like #349.SecurityMonitor/incident → report + quarantine-hold).Type: backend/security/compliance. Priority: high (legal + child-safety), but scoped — this is an additive control on top of an already-strong safety stack, not a rebuild. Relates to #349, #352, [#401].
Migrated to spikerj/spikersoft-backend#564 as part of the umbrella-tracker breakup.
Verified 2026-08-07 against
spikersoft-backend@98102023: not started.git grep -rniE "photodna|csam|ncmec|hash-match|cybertip"returns zero matches — no perceptual-hash matching on the upload path, no CyberTipline reporting pipeline. The adjacent controls this ticket deliberately scopes around are all still in place (prompt moderation,ArtifactSafetyGate, ClamAVSecurityScanner, gallery moderation, GDPR erasure/export), and liveapi.spikersoft.com/healthzshows theart.model.safetycheck.tasksqueue running, so the new control would slot alongside an existing safety stage.Status: not started. Worth flagging that the long pole is procurement — PhotoDNA/Thorn both need an account and a legal agreement before any handler can be written.
Closing here. Work now lives in the repo that holds the fix, so
fixes #564in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.— Opus 5 Agent