Pastebin

Untitled

text 13 views Created: October 28, 2026 at 21:31:33 EDT
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
================================================================================
SCREECHVR: FINAL SECURITY RESEARCH CORRECTION, VALIDATION & COMPLETE TEXT BUNDLE
================================================================================

1. COVER AND SCOPE
================================================================================

Project name: ScreechVR (Voideration Anti-Cheat)
Research date: 2026-10-29 (final correction pass v03)
Purpose: Final correction, validation, and consolidation pass. Resolves
inconsistencies, verifies findings against actual project and official
documentation, produces one self-contained text file for independent review.

No implementation was performed. No project files were modified. No services were
deployed. No production data was changed. No credentials were reproduced.

Research-only phase. Awaiting explicit approval before any code is written.

Budget constraint: €0 additional monthly spend. Game-server hosting already
handled (Photon Cloud relay, not authoritative). No new paid services.

================================================================================
2. EXECUTIVE FINDINGS
================================================================================

Most important verified findings:
1. ScreechVR uses Unity 2021.3 LTS, Photon PUN 2 + Voice, PlayFab, Meta/Oculus SDK,
   Cloudflare Worker. IL2CPP for Quest builds. No dedicated authoritative game server.
   Existing server infrastructure is relay-only (Photon Cloud) or client-hosted
   (Master Client). Game-server hosting being "handled" does not mean authoritative
   gameplay exists.
2. Currency flow: Oculus_Login.cs AddCurrency/RemoveCurrency update local _currency
   before server call. PlayFab AddUserVirtualCurrency accepts client-specified amount
   (validates session, not amount). CONDITIONAL: depends on PlayFab title settings
   (client access). If enabled, CRITICAL vulnerability. Server-authoritative grants
   recommended regardless.
3. Moderator status stored in PlayFab UserData "Moderator" key. PlayFab UserData is
   client-writable by default. Check_Mod.cs sets AccountPref after 5s timeout.
   CONDITIONAL: verify in PlayFab dashboard. If client-writable, CRITICAL.
4. Bans enforced client-side only: KickIfBanned polls GetAccountInfo every 5s;
   Kick_Player triggers Application.Quit. Modified client can ignore both.
   Server-side enforcement via Photon custom auth is the fix (connect-time rejection).
5. No movement validation: Player.cs locomotion all client-side. No server validation.
   Movement exploits can only be detected heuristically, not prevented (no dedicated server).
6. Master client is a player, not a server. AutomaticallySyncScene=true allows master
   to force scene loads on all clients.
7. No anti-cheat scripts exist. No server-side validation of movement, position, or score.
8. Photon RPCs lack ownership checks, param validation, rate limits (ThusterController
   floods, Flash_Light held-button floods).
9. Null crashes throughout (PlayerSpawner, Hand_Physic, Monster_Track, etc.) unguarded.
10. AppEntitlementCheck logs only, does not quit on failure.
11. Photon auth: PlayFab provides GetPhotonAuthenticationToken. Photon's custom auth
    delegates to PlayFab's /photon/authenticate endpoint (server-to-server). The Worker
    does NOT validate the Photon token independently. PlayFab's endpoint validates the
    token. If a custom Worker is needed (for ban checks), it must forward to PlayFab's
    /photon/authenticate endpoint. CORRECTED: earlier claim that GetAccountInfo validates
    Photon token was incorrect. GetAccountInfo verifies account existence and ban status,
    NOT Photon token validity.
12. Meta attestation: official docs now accessible. Token valid 24h by default (configurable).
    Server must validate: exp (within 24h), nonce (one-time use), timestamp (recent),
    app_integrity_state (StoreRecognized), package_cert_sha256_digest (matches),
    device_integrity (Advanced or Basic). Rate limits: 100 req/hour, 200 req/day per device.
    security_update_pending_days only available if device_state is Advanced or Basic.
13. Meta User Verification: getUserProof returns proof of account control. Server validates
    nonce (server-generated, one-time use). DIFFERENT from App Attestation challenge_nonce.
    User Verification proves identity; App Attestation proves device/app integrity.
    NOTE: "hardware-bound" is inaccurate. Meta identity proves account control, not
    device binding.
14. Photon pricing (VERIFIED from official page): free tier 20 CCU (dev only). 100 CCU = $95/12mo
    (one-time). 500 CCU = $95/mo. 1000 CCU = $185/mo. 2000 CCU = $370/mo. Premium Cloud =
    $0.29/CCU, min $580/mo. Voice separate. PUN 2 in maintenance/LTS mode.
15. Heartbeat cost: 10s = 8,640 req/player/day. At 100 CCU = 864,000 req/day (exceeds free
    tier). 30s = 2,880 req/player/day. At 100 CCU = 288,000 req/day (exceeds free tier).
    5-min = 288 req/player/day. At 100 CCU = 28,800 req/day (within free tier).
    Recommendation: 30s request (no D1 write) + 5-min D1 write. Or KV for session state.

Highest-severity unresolved issues:
1. PlayFab UserData "Moderator" key writability (CRITICAL if client-writable).
2. CloudScript/Azure Functions deployment status (unknown).
3. Meta attestation API availability to ScreechVR (docs accessible, eligibility unverified).
4. Photon custom auth configuration (dashboard not inspected).
5. PlayFab PurchaseItem price validation (assumed, unverified).

Recommended next step: Verify the 5 critical items above (requires dashboard access),
then begin Stage 1 implementation after user approval.

================================================================================
3. PROJECT AND RESEARCH COVERAGE
================================================================================

Source files inspected:
- Assets/Scripts/Oculus_Login.cs (auth, currency, ban, MOTD, title data, inventory)
- Assets/Scripts/ScreechApi.cs (worker HTTP)
- Assets/Scripts/PhotonVRManager.cs (networking, rooms, cosmetics, gun)
- Assets/Scripts/PlayerSpawner.cs (spawn/despawn)
- Assets/Scripts/UsernameValidator.cs (content creator check)
- Assets/Scripts/AppEntitlementCheck.cs (Oculus entitlement, log only)
- Assets/Scripts/KickIfBanned.cs, Kick_Player.cs (ban/kick)
- Assets/Scripts/LevelSelect.cs, MapLoader.cs, sceneyessss.cs (scene loading)
- Assets/Scripts/Gamemode_System.cs, GamemodeManager.cs, Gamemode_.cs, DeployGamemode.cs
- Assets/Scripts/GetCosmetics.cs, SecondaryCosmetics.cs, BuyCosmetic.cs, Cosmetic_Yes.cs
- Assets/Scripts/TagManager.cs, TagPlayer.cs, TagLeaderboard.cs
- Assets/Scripts/BestJumpscare.cs (collider kill)
- Assets/Scripts/NewGorillaLocomotionScripts/Player.cs (locomotion)
- Assets/Scripts/Hand_Physic.cs (grab/physics)
- Packages/manifest.json (SDKs)
- Assets/Resources/GorillaPrefabs/Gorilla Rig.prefab

Research documents reviewed:
- research/ (27 reports + README + FINAL_RESEARCH_SUMMARY)
- research/FINAL_SECURITY_ARCHITECTURE/ (26 deliverables)
- docs/screechvr-technical-map-2026-10-28.md
- docs/voideration-screechvr-architecture.md
- docs/voideration-anticheat-research.md
- docs/voideration-anticheat-review.md
- research/QUEST_MODIFICATION_THREAT_CATALOG.md
- SHARED-MEMORY.md, AGENTS.md

Claims checked against official documentation:
- PlayFab: AddUserVirtualCurrency, PurchaseItem, LoginWithCustomID, GetPhotonAuthenticationToken, BanUsers, GetTitleData, GetUserData/UpdateUserData
- Photon: custom authentication response codes (0=incomplete, 1=success, 2=failure, 3=invalid params), PUN 2 maintenance mode, pricing (free 20 CCU, 100 CCU $95/12mo, 500 CCU $95/mo, 1000 CCU $185/mo)
- Cloudflare: Workers free tier (100k req/day), D1 free tier (5GB, 5M reads/day, 100k writes/day), KV free tier
- Meta: Attestation API (now accessible, full docs retrieved), User Verification (ps-ownership, partially accessible), device ban (server-to-server)
- OWASP: API Security Top 10 2023, Cryptographic Storage Cheat Sheet

Items that could not be accessed:
- PlayFab dashboard (CloudScript, UserData permissions, PurchaseItem config, ban enforcement)
- Photon dashboard (custom auth config, anonymous client setting, dev/prod app IDs)
- Meta developer portal (User Verification full docs, attestation eligibility)

================================================================================
4. Photon authentication correction
================================================================================

Token distinctions (CRITICAL - not interchangeable):
- PlayFab Session Ticket: issued by PlayFab on login, used for PlayFab API calls and worker /redeem. Lifetime: session duration (hours). Verified by PlayFab (GetAccountInfo).
- Photon Custom Auth Token: issued by PlayFab GetPhotonAuthenticationToken, used for Photon connection. Lifetime: short (minutes). Verified by Photon's servers (server-to-server call to custom auth URL).
- Meta Oculus ID: identifier from Oculus Platform SDK. Used as PlayFab CustomId. Proves nothing by itself; must be verified via Meta User Verification.
- Meta User Proof: one-time proof of account control (getUserProof). Verified server-side with Meta. NOT currently used in ScreechVR.
- Meta Attestation Token: device/app integrity token. Verified server-side with Meta. UNVERIFIED availability for ScreechVR.

Correct authentication flow (PlayFab Photon integration, standard):
1. Client: Oculus Core.Initialize + Users.GetLoggedInUser -> Oculus ID + username.
2. Client: PlayFab LoginWithCustomID (Oculus ID, CreateAccount=true) -> PlayFab session ticket.
3. Client: PlayFab GetPhotonAuthenticationToken (photonAppId) -> Photon custom auth token.
4. Client: Photon ConnectUsingSettings with custom auth params (Photon token as auth param).
5. Photon server: calls custom auth URL (PlayFab's /photon/authenticate or custom worker) with auth params (server-to-server).
6. Backend: validates Photon token via PlayFab's documented /photon/authenticate endpoint. Returns allow/deny + UserId.
7. Photon enforces result. Client cannot bypass.

PlayFab Photon integration (standard flow, from official docs):
- PlayFab provides GetPhotonAuthenticationToken which returns a token.
- Photon's custom auth URL receives this token (server-to-server).
- The backend at that URL validates the token with PlayFab.
- PlayFab's documented endpoint: https://<titleId>.playfabapi.com/photon/authenticate
- The PlayFab UserId is sent as the 'username' parameter and the Photon token as the 'token' parameter.
- If using a custom worker instead, the worker receives the Photon token and must validate it. The worker CANNOT use GetAccountInfo to validate the Photon token (GetAccountInfo verifies account existence, not token validity). The worker must either:
  a) Forward the request to PlayFab's /photon/authenticate endpoint (recommended), or
  b) Use another documented verification mechanism (if available).
- If no documented verification mechanism exists, the custom worker design is UNRESOLVED. Use PlayFab's standard /photon/authenticate endpoint.

Custom Worker authentication (if used for ban checks):
- Worker receives Photon token from Photon's servers (server-to-server, not client).
- Worker forwards token to PlayFab's /photon/authenticate endpoint for validation.
- After PlayFab validates, worker checks ban status via PlayFab (GetAccountInfo or ban list) using its own admin key.
- Worker returns allow/deny + UserId to Photon.
- Credential exposure: Photon token is sent over HTTPS (encrypted). Worker logs should not include the token. URL params may be logged by proxies; use POST body for sensitive data.

Photon custom auth response codes (verified from official docs):
- ResultCode 0: incomplete (multi-step auth).
- ResultCode 1: success (allow).
- ResultCode 2: failure (deny).
- ResultCode 3: invalid parameters.
- Photon enforces: deny on failure, allow on success.

Configuration uncertainties (dashboard not inspected):
- Is custom auth configured in Photon dashboard?
- Is "Allow anonymous clients" disabled?
- Is the auth URL pointing to PlayFab's /photon/authenticate or a custom worker?
- Are dev and prod app IDs separate?
- Does the client include the Photon token (not session ticket) in auth params?

Failure/replay behavior:
- Missing credentials: Photon denies connection (if custom auth configured).
- Invalid token: Photon denies connection.
- Expired session: Photon token expired -> worker/PlayFab returns deny.
- Revoked session: worker must track session IDs and reject revoked ones (not currently implemented).
- Banned account: worker checks ban status (PlayFab GetAccountInfo) -> deny.
- Anonymous client: if "Allow anonymous clients" enabled, client can connect without auth (VULNERABILITY).
- Backend timeout: Photon's behavior on timeout is UNVERIFIED. May allow or deny.
- Backend outage: if worker is down, Photon custom auth fails -> Photon may deny or allow (depends on config).

Tests required:
- Invalid Photon credentials -> connection denied.
- Banned user -> connection denied.
- Anonymous client -> connection denied (if anonymous disabled).
- Expired session -> connection denied.
- Backend timeout -> connection denied (verify Photon behavior).
- Old client -> connection denied (version check).

================================================================================
5. Meta identity verification correction
================================================================================

Current flow (verified from Oculus_Login.cs):
Oculus ID -> PlayFab LoginWithCustomID (no proof verification) -> PlayFab session ticket.

VULNERABILITY: Client provides Oculus ID without proof. Modified client can claim any Oculus ID.

Proposed fix (not implemented):
1. Client: Oculus Core.Initialize + Users.GetLoggedInUser -> Oculus ID + username.
2. Client: Request Meta User Proof (getUserProof) with server-generated nonce.
   - Server generates nonce, sends to client.
   - Client calls getUserProof(nonce).
   - Meta returns proof containing the nonce.
3. Client: Send proof + Oculus ID to backend (worker).
4. Backend: Verify proof with Meta's servers (server-to-server).
   - Backend sends proof to Meta verification endpoint.
   - Meta verifies nonce matches, returns verified identity.
5. Backend: If verified, link/create PlayFab account (LoginWithCustomID with verified Oculus ID).
6. Backend: Issue session token (JWT) bound to verified identity.

CRITICAL DISTINCTION (corrected wording):
- Meta User Verification (getUserProof): proves user controls the Meta account. The proof is tied to the Meta account, not to device hardware. "Hardware-bound" is inaccurate - the proof verifies account control, not device binding. The Oculus ID is associated with a Meta account, but the proof verifies that the current user controls that account.
- Meta App Attestation (GetIntegrityToken): proves device/app integrity. Uses server-generated challenge_nonce. One-time use.
- These are DIFFERENT APIs with DIFFERENT nonce mechanisms. Do not confuse them.

SDK and permission uncertainties:
- Unity 2021.3.32f1: Meta SDK version compatibility unknown.
- Required permissions: Data Use Checkup (User ID, User Profile, Device Ban).
- Account migration: existing players need migration path.
- Duplicate account handling: same Meta ID, multiple PlayFab accounts.

Security boundaries:
- Meta identity verification proves user controls the Meta account.
- Does NOT prove game integrity, no cheating, legitimate gameplay.
- Identity is one layer. Must combine with server-side validation and detection.

Tests required:
- Invalid Meta proof -> login denied.
- Replay of Meta proof -> login denied (nonce must be one-time).
- Account linking without proof -> login denied.
- Stale proof (expired nonce) -> login denied.

================================================================================
6. Meta attestation correction
================================================================================

Current documented API behavior (from official Meta docs, fetched 2026-10-29):

API: ovr_DeviceApplicationIntegrity_GetIntegrityToken(const char *challenge_nonce)
- Platform: Android only. Quest 2, Quest Pro, Quest 3, Quest 3S.
- Requires: Platform SDK v55+, Meta Horizon OS v55+.
- Wi-Fi required (attestation server communication).

Flow:
1. Server generates challenge_nonce (Base64URL, 22-172 chars, cryptographically random, one-time use).
2. Client calls GetIntegrityToken(challenge_nonce) -> Meta attestation server collects security signals -> generates attestation token.
3. Client sends token to app server.
4. App server sends token + access_token to Meta verification endpoint:
   https://graph.oculus.com/platform_integrity/verify?token=<attestation_token>&access_token=<access_token>
5. Meta returns claims (success) or error (invalid signature, token expired).

Token claims (Base64URL-encoded):
- request_details: exp (expiration, default 24h), nonce (must match challenge_nonce), timestamp (UTC seconds, token creation time).
- app_state: app_integrity_state (StoreRecognized/NotRecognized/NotEvaluated), package_cert_sha256_digest (SHA-256 of signing cert), package_id, version.
- device_state: device_integrity_state (Advanced/Basic/NotTrusted), unique_id (changes every 30 days), security_update_pending_days (only if Advanced/Basic).

Token validation (server must check):
- exp: within 24 hours (default, configurable in dashboard). This is the token's expiration time.
- nonce: matches challenge_nonce (one-time use, prevent replay). This is the replay protection mechanism.
- timestamp: recent (within a few minutes). This is the freshness check, separate from exp.
- app_integrity_state: StoreRecognized (legitimate installation).
- package_cert_sha256_digest: matches expected signing cert hash.
- device_integrity_state: Advanced or Basic (NotTrusted = unlocked bootloader or invalid OS).

Replay protection:
- challenge_nonce must be unique, cryptographically random, used only once.
- Server stores nonce, verifies returned nonce matches, then discards.
- Nonce length: 22-172 characters (Base64URL).

Rate limits:
- 100 requests/hour per device.
- 200 requests/day per device.
- Token caching recommended (reuse within validity period, less than 24h).

security_update_pending_days:
- Number of days since oldest public security patch missing.
- 0 = fully up to date.
- Only available if device_state is Advanced or Basic.
- Use caution: aggressive use may lock out slow-updating users.

device_integrity_state meanings (from official docs):
- Advanced: bootloader locked, valid Android OS, no signs of system compromise.
- Basic: bootloader locked, valid Android OS, but some integrity checks failed (possibly rooted).
- NotTrusted: bootloader unlocked, or invalid Android OS image.

Device ban (server-to-server):
- Uses unique_id (changes every 30 days) and ban_id (persistent).
- Ban duration: 0-52560000 minutes (100 years max).
- Requires Data Use Checkup approval.
- Ban enforcement on server side (check device_ban section in token claims).

API configuration (dashboard):
- Device Integrity State Bypass: enabled by default (testing devices always Advanced).
- Token Expiration Duration: default 24h, configurable (shorter = more secure, more API calls).

Best practices (from official docs):
- Validate attestation tokens server-side only.
- Handle errors securely (exponential backoff, treat failure as NotTrusted).
- Validate token securely (exp, nonce, timestamp, app_integrity_state, package_cert, device_integrity).
- Include unique elements in challenge_nonce (cryptographically secure random, transaction ID).
- Bind sensitive requests to challenge_nonce (hash critical request params + nonce).
- Opt for account limitations instead of binary blocking (allow with restrictions).

What remains unverified for ScreechVR:
- API availability to all Quest developers vs gated (Data Use Checkup required for device ban).
- Whether ScreechVR's Meta app has the required permissions (User ID, User Profile, Device Ban).
- Unity 2021.3.32f1 + Platform SDK v55+ compatibility.
- Whether attestation works for sideloaded builds (app_integrity_state = NotRecognized for sideloaded).
- Eligibility requirements (may require Meta approval).

Handling policy (proposed):
- Trusted (Advanced, StoreRecognized): normal access.
- Suspicious (Basic): flag + increased monitoring, allow with restrictions.
- Untrusted (NotTrusted or NotRecognized): restrict sensitive actions (no purchases, no leaderboard submissions), flag for review.
- Unsupported (older device, SDK < v55): allow with warning (log for analysis).
- Unavailable (service outage, network failure): allow with flag (service failure, not user's fault). Do not block.
- Inconclusive (errors, missing claims): flag + manual review. Do not auto-ban.

================================================================================
7. PlayFab and privilege correction
================================================================================

Currency API findings (VERIFIED from source code):
- Oculus_Login.cs: AddCurrency(int amount) calls PlayFab AddUserVirtualCurrency with client-specified amount.
- PlayFab validates session ticket but NOT amount. Client can grant arbitrary currency.
- BuyCosmetic.cs checks local _currency >= Price before calling PlayFab PurchaseItem.
- PlayFab PurchaseItem validates price server-side against catalog (STRONG EVIDENCE, verify in dashboard).
- Currency_Code = "HC". _currency is client-held int.

CONDITIONAL: Whether clients can actually call AddUserVirtualCurrency depends on PlayFab title settings (client access). If client access is disabled, only server-side calls work (and the vulnerability doesn't exist). If enabled, it's critical. VERIFY in PlayFab dashboard.

Moderator permissions (UNVERIFIED):
- Oculus_Login.cs: CreateKeyIfNot creates "Moderator"="FALSE" in PlayFab UserData.
- PlayFab UserData is client-writable by default (STRONG EVIDENCE from PlayFab docs).
- If client-writable, any client can set "Moderator"="TRUE" -> self-promotion.
- Check_Mod.cs sets AccountPref = Moderator if UserData "Moderator" == "TRUE".
- Mod_Toggle.cs opens ModMenu if DefaultQueue == "MODDED".
- CRITICAL: Verify PlayFab UserData write permissions in dashboard. If client-writable, immediate critical vulnerability.

Purchase and inventory checks:
- PlayFab PurchaseItem validates price server-side against catalog (STRONG EVIDENCE, verify).
- Client gates on local balance (cosmetic issue, not security).
- Inventory: GetUserInventory (server-side). Cosmetic ownership should be verified server-side.

Ban enforcement:
- PlayFab bans are server-side (admin API). Ban status checked via GetAccountInfo.
- KickIfBanned polls every 5s (client-side, ignorable).
- No server-side kick enforcement (requires Photon custom auth ban check).

Other unresolved PlayFab flows:
- CloudScript/Azure Functions: none found in repo. Verify in dashboard.
- SpokesSigmaIAP receipt validation: not fully read.
- GDH leaderboard submission path: unknown anti-cheat.
- ATM_TAB/Atm_Manager: not deeply read.
- Leaderboard validation: unknown.

================================================================================
8. Backend and database cost correction
================================================================================

Current pricing sources (verified 2026-10-29):

Cloudflare:
- Workers: free 100k req/day. Paid: $5/mo + $0.50/million requests.
- D1: free 5GB, 5M reads/day, 100k writes/day. Paid: $0.001/100k reads, $1.00/1M writes.
- KV: free 100k reads/day, 1k writes/day. Paid: $0.50/million reads.
- R2: free 10GB storage, 1M reads/mo, 1M writes/mo. Paid: $0.015/GB/mo.
- Pages: free (unlimited static sites).

PlayFab: free tier (limits vary, verify in dashboard).

Photon (VERIFIED from official pricing page 2026-10-29):
- Free tier: 20 CCU (development only, 60 GB traffic/month, capped, no burst).
- 100 CCU: $95 one-time (12-month term, ~$8/mo averaged). 0.3 TB traffic. Capped, no burst.
- 500 CCU: $95/mo. 1.5 TB traffic. CCU burst included.
- 1000 CCU: $185/mo. 3.0 TB traffic. CCU burst.
- 2000 CCU: $370/mo. 6.0 TB traffic. CCU burst.
- Premium Cloud: $0.29/CCU invoiced, min $580/mo (2000 CCU + 6 TB). Up to 50,000 CCU.
- Enterprise: custom (unlimited CCU, SLA, dedicated servers, server-authoritative plugins).
- Traffic overage: $0.05/GB (Europe/Canada/US) or $0.10/GB (Asia/etc.).
- Voice is separate (Photon Voice has its own pricing).
- 1 CCU ~ 20 DAU ~ 400 MAU (rule of thumb).
- Downgrade/upgrade anytime. Unused fees credited.
- PUN 2 is in maintenance/LTS mode. Photon recommends Fusion for new projects.

Workload calculations:
- 10s heartbeat: 6 req/min = 360 req/hour = 8,640 req/day per player.
  At 50 CCU: 432,000 req/day (exceeds free tier 100k/day).
  At 100 CCU: 864,000 req/day (exceeds free tier 8.6x).
- 30s heartbeat: 2 req/min = 120 req/hour = 2,880 req/day per player.
  At 50 CCU: 144,000 req/day (exceeds free tier 1.4x).
  At 100 CCU: 288,000 req/day (exceeds free tier 2.9x).
- 60s heartbeat: 1 req/min = 60 req/hour = 1,440 req/day per player.
  At 50 CCU: 72,000 req/day (within free tier).
  At 100 CCU: 144,000 req/day (exceeds free tier 1.4x).
- 5-min heartbeat: 0.2 req/min = 12 req/hour = 288 req/day per player.
  At 50 CCU: 14,400 req/day (within free tier).
  At 100 CCU: 28,800 req/day (within free tier).
  At 1000 CCU: 288,000 req/day (exceeds free tier 2.9x).

D1 write calculations:
- Every heartbeat write (30s): 2,880 writes/day per player.
  At 50 CCU: 144,000 writes/day (exceeds free tier 100k/day).
  At 100 CCU: 288,000 writes/day (exceeds 2.9x).
- Every 5-min write: 288 writes/day per player.
  At 50 CCU: 14,400 writes/day (within free tier).
  At 100 CCU: 28,800 writes/day (within free tier).
  At 1000 CCU: 288,000 writes/day (exceeds 2.9x).

Alternative heartbeat designs:
- 30s request to worker (no D1 write): session liveness tracked in KV (eventual consistency).
- 5-min D1 write: session persistence (strong consistency).
- Batch telemetry: send every 30s instead of per-event.
- Periodic persistence: write to D1 every 5 min, not every heartbeat.
- Use KV for session state (eventual consistency acceptable for liveness).

Costs at requested CCU scenarios:
- 50 CCU: $1-2/mo (domain only, all free tiers). Photon free tier (20 CCU) EXCEEDED -> upgrade to $95 one-time (12-month term).
- 100 CCU: $5-16/mo (Cloudflare) + $95 one-time/12mo (Photon). Total: $5-16/mo + $95/yr.
- 500 CCU: $16-33/mo (Cloudflare) + $95/mo (Photon) = $111-128/mo.
- 1000 CCU: $16-40/mo (Cloudflare) + $185/mo (Photon) = $201-225/mo.
- 5000 CCU: $65-130/mo (Cloudflare) + $370+/mo (Photon) = $435+/mo.

Key insight: Photon is the cost bottleneck. Cloudflare scales cheaply. PlayFab scales with usage.

Free-tier limits and what happens when exceeded:
- Cloudflare: 429 Too Many Requests. Backend auth fails closed (deny connections).
- PlayFab: API calls fail. Client gets error. Game may not function.
- Photon: connection refused. Game unplayable (no multiplayer).

================================================================================
9. Multi-layer architecture review
================================================================================

13 layers (independent where possible):
1. Meta User Verification (platform) - identity proof. If bypassed: attacker claims any Oculus ID.
2. Meta Entitlement (platform) - app ownership. If bypassed: unentitled clients stay.
3. Meta Attestation (platform, optional) - device/app integrity. If bypassed: no device integrity signal.
4. PlayFab Auth (backend) - account identity. If bypassed: attacker creates accounts with arbitrary IDs.
5. Photon Custom Auth (network) - room admission. If bypassed: banned/invalid players connect.
6. Worker session validation (worker) - session validity. If bypassed: stale/revoked sessions work.
7. Backend authorization (worker) - API permissions. If bypassed: attacker calls any API.
8. Server-side economy (PlayFab/worker) - currency/inventory. If bypassed: attacker mints currency.
9. Server-side bans (PlayFab) - enforcement. If bypassed: banned player returns.
10. Detection engine (worker) - behavioral flags. If bypassed: suspicious behavior not flagged.
11. Rate limiting (worker/Cloudflare) - abuse prevention. If bypassed: attacker floods endpoints.
12. Audit logging (worker) - accountability. If bypassed: no evidence trail.
13. Dashboard security (worker) - admin protection. If bypassed: unauthorized admin access.

Common-mode failures:
- If Meta platform compromised: layers 1-3 fail. Layers 4-13 still function.
- If PlayFab compromised: layers 4, 8, 9 fail. Layers 1-3, 5-7, 10-13 still function.
- If worker compromised: layers 6, 7, 10, 11, 12, 13 fail. Layers 1-5, 8, 9 still function.
- If Photon compromised: layer 5 fails. Layers 1-4, 6-13 still function.

Attack-to-defense matrix: see research/ANTI_CHEAT_PREVENTION_DETECTION_MATRIX.md.

================================================================================
10. Photon RPC and gameplay authority findings
================================================================================

Actual enforcement points:
- Photon Cloud: relays RPCs, no param validation, no rate limiting, no game logic.
- Photon Master Client: player with flag, controls room properties and scene sync. Untrusted.
- Worker: can enforce rate limits on Worker API calls only (not Photon RPCs).
- PlayFab: can enforce bans, inventory, currency (server-side).
- Dedicated server: not available (v2+). Game-server hosting is "handled" but this is relay-only (Photon Cloud), not authoritative.

Client-controlled state (cannot be prevented without dedicated server):
- Movement/position (Player.cs, locomotion).
- Tag/infection state (TagPlayer.cs, TagManager.cs RPCs).
- Score/leaderboard submissions (GDH leaderboard).
- Cosmetic equip (GetCosmetics.cs, Photon props).
- Game state (Gamemode_System.cs, CurrentMode).

What can be prevented (server-side):
- Currency minting (move grants to worker/CloudScript).
- Moderator spoof (server-side role verification).
- Ban bypass (Photon custom auth ban check).
- Cosmetic spoof (backend inventory check).
- Version mismatch (title data + custom auth).

What can only be detected (heuristic, not prevention):
- Movement exploits (speed, teleport, fly).
- RPC floods (rate limit + flag).
- Tag/Infection spoof (flag non-tagger RPCs).
- Leaderboard faking (flag anomalies).
- Master client abuse (log + flag).

Recommended short-term (v1): Backend validation + heuristic detection + manual review.
Recommended long-term (v2+): Dedicated authoritative server for movement, scoring, bans.

================================================================================
11. Provider and authentication comparison corrections
================================================================================

Revised findings:
- Meta User Verification: strongest identity proof (account control, NOT hardware-bound). UNVERIFIED availability.
- PlayFab: good for auth/inventory/bans. Custom ID login is client-provided (not proof). Add Meta User Verification.
- Firebase Auth: good Unity support, free tier, but adds complexity. No clear benefit over PlayFab for Quest game.
- Supabase Auth: free tier pauses after 7 days inactivity. Not suitable for production without paid plan.
- Nakama: best open-source option. Authoritative multiplayer. High migration cost (20-30 weeks). Hosting $5-50/mo.
- Appwrite/PocketBase: limited Unity support. Not recommended.
- Keycloak/Ory/Authentik: heavy, overkill for solo dev. Self-hosted ops burden.
- Auth0/Clerk: good free tiers (7.5k-10k MAU). MAU limits. Not Quest-specific.
- AWS Cognito: 50k MAU free. Complex, AWS lock-in.
- Cloudflare: good for API/backend. No native game-user identity. Use with PlayFab.

Recommended: Meta User Verification + PlayFab (identity) + Cloudflare worker (API/backend) + Photon (networking). No new provider needed for v1.

Corrected free-tier limitations:
- Cloudflare Workers: 100k req/day (free). Exceeded -> 429 or $5/mo paid.
- Cloudflare D1: 5GB, 5M reads/day, 100k writes/day (free). Exceeded -> paid.
- PlayFab: free tier limits (verify in dashboard).
- Photon: free tier 20 CCU (dev only). Exceeded -> $95/12mo for 100 CCU.
- Firebase: Spark plan (free, no credit card). Blaze (pay-as-you-go) for functions.
- Supabase: free tier pauses after 7 days inactivity.

================================================================================
12. Corrected final architecture
================================================================================

Text-based architecture diagram:

[Quest Client (Unity/IL2CPP)]
    | Oculus Auth (Core.Initialize + Users.GetLoggedInUser)
    | Meta User Proof (getUserProof, server-generated nonce)
    | PlayFab Login (LoginWithCustomID, verified Oculus ID)
    | PlayFab Session Ticket
    | Photon Connect (Custom Auth -> Cloudflare worker)
    | Heartbeat (every 30s -> worker)
    | Telemetry (movement samples, events -> worker)
    v
[Cloudflare Worker (trusted)]
    | /validate-session (Meta proof + PlayFab ticket + ban check)
    | /heartbeat (session liveness, duplicate detection)
    | /report-flag (telemetry -> detection rules)
    | /ban-check (real-time ban status)
    | /redeem (existing, PlayFab ticket required)
    | /motd (existing, public)
    | /updateplayers (existing, public, rate-limited)
    v
[D1 Database (SQLite)]
    sessions, players, flags, bans, audit_log, ccu_snapshots, webhooks, detection_rules, evidence
    v
[PlayFab (trusted backend)]
    Auth, inventory, currency, bans, title data, leaderboards, user data
    v
[Photon Cloud (semi-trusted relay)]
    Rooms, RPCs, sync, voice. Master client = player.
    Custom auth -> worker (server-to-server)
    v
[Cloudflare Pages (dashboard)]
    React + Tailwind + shadcn/ui. Auth: email+password+TOTP. JWT. RBAC.
    Reads from worker API only.

Sources of truth:
- Player identity: PlayFab (verified Oculus ID).
- Session validity: Worker (PlayFab ticket + session tracking).
- Ban status: PlayFab (server-side).
- Currency balance: PlayFab (server-side after fix).
- Inventory/cosmetics: PlayFab (server-side).
- Movement/position: Client (untrusted, heuristic detection only).
- Game state (scores, kills): Client (untrusted).
- Room state: Photon (relay, master client untrusted).
- Moderator status: PlayFab (server-side after fix).
- CCU: Worker (heartbeat-based).
- Audit log: Worker D1 (append-only).

Failure behavior:
- PlayFab down: fail closed for auth (deny new connections), fail open for gameplay (existing sessions continue), bans still enforced from cache.
- Worker down: Photon custom auth fails -> Photon denies connections (fail closed). Existing sessions continue.
- D1 down: audit log/flags delayed, core auth still works (worker validates via PlayFab directly).
- Photon down: game unplayable (no multiplayer). Single-player not affected.

Security guarantees (current vs proposed vs tested):
- Currency cannot be minted: CURRENT=no (client-trusted), PROPOSED=yes (server-side), TESTED=no.
- Bans cannot be bypassed: CURRENT=no (client-side), PROPOSED=yes (custom auth), TESTED=no.
- Moderator status cannot be spoofed: CURRENT=unknown (verify UserData), PROPOSED=yes (server-side), TESTED=no.
- Cosmetics verified against inventory: CURRENT=no, PROPOSED=yes, TESTED=no.
- Version enforcement: CURRENT=partial (title data, client can ignore), PROPOSED=yes (custom auth), TESTED=no.
- Movement exploits: CURRENT=no, PROPOSED=detect only (heuristic), TESTED=no.
- RPC floods: CURRENT=no, PROPOSED=rate limit, TESTED=no.

================================================================================
13. Threat-to-defense matrix
================================================================================

(See research/ANTI_CHEAT_PREVENTION_DETECTION_MATRIX.md for full 18-row matrix.)

Key threats and defenses:
1. Modified APK -> Meta entitlement + version enforcement + server-side ban check.
2. Client-trusted currency -> Move grants to server-side (worker/CloudScript). CONDITIONAL: depends on PlayFab title settings.
3. Moderator spoof -> Server-side role verification (PlayFab server data). CONDITIONAL: depends on UserData writability.
4. Ban evasion -> Photon custom auth ban check on connect + KickIfBanned (supplementary).
5. Movement exploits -> Heuristic detection (speed/teleport flags) + manual review. NOT auto-ban.
6. Cosmetic spoof -> Backend inventory verification + flag mismatch.
7. Leaderboard faking -> Server-side score validation or remove from leaderboard.
8. IAP bypass -> PlayFab PurchaseItem validates price server-side + server-side balance check.
9. Tag/Infection spoof -> Rate limit + ownership check + flag non-tagger RPCs.
10. Master client abuse -> Minimize master authority, move room state to backend.
11. RPC flood -> Per-player rate limits + flag.
12. Null crashes -> Guard null refs + server-side crash detection.
13. Duplicate session -> Heartbeat-based detection + kick older.
14. Version spoof -> Title data + custom auth version check.
15. Alt account ban evasion -> Hardware + IP overlap detection.
16. Attestation failure -> Flag + manual review. Do not auto-ban.
17. Frida/injection -> Server-side enforcement limits blast radius. Client detection = low-conf flag.
18. Memory modification -> Server-side validation of all valuable state.

================================================================================
14. Implementation roadmap
================================================================================

Stage 0: Close research gaps (1 week)
- Verify PlayFab UserData "Moderator" writability.
- Verify CloudScript/Azure Functions deployment.
- Verify PlayFab PurchaseItem price validation.
- Verify Meta attestation availability (if possible).
- Verify Photon custom auth configuration.
- Effort: 1 week. Risk: low.

Stage 1: Backend foundation (2-3 weeks)
- Cloudflare worker extensions: /validate-session, /heartbeat, /report-flag, /ban-check.
- D1 database schema.
- Photon custom auth integration.
- PlayFab integration: validate session tickets, check bans.
- Acceptance: Photon connection fails for banned/invalid sessions; heartbeat tracks CCU.

Stage 2: Detection (2-3 weeks)
- Movement telemetry collection.
- Rules S-001, S-002, S-005, S-006, S-008.
- Flag creation with confidence + evidence storage.
- Review queue API.
- Acceptance: flags for synthetic cheats; no false positives on clean sessions.

Stage 3: Dashboard (2-3 weeks)
- Auth (email+password+TOTP), JWT, RBAC.
- Overview, players, flags, bans, audit log pages.
- Ban issue/revoke with Discord webhook.
- Acceptance: owner can log in, view flags, issue ban, ban appears in PlayFab.

Stage 4: Currency/cosmetic protection (1-2 weeks)
- Move currency grants to worker/CloudScript.
- Backend inventory verification for cosmetics.
- Acceptance: client cannot grant itself currency; cosmetic spoof flagged.

Stage 5: Testing & hardening (1-2 weeks)
- Pen test, load test (k6), false-positive regression, backup restore.
- Acceptance: all tests pass, no critical findings.

Stage 6: Controlled rollout (1 week)
- Staging with PCDEBUG (two-editor test).
- Limited QA rollout, monitoring, gradual expansion.

Total: ~9-14 weeks solo, part-time. Depends on Stage 0 findings.

================================================================================
15. Security test register
================================================================================

All tests are planned, not executed. No fabricated results.

Authentication tests:
- Invalid identity proof -> login denied.
- Arbitrary Custom ID -> login denied (if Meta User Verification implemented).
- Expired/revoked session -> connection denied.
- Replay of one-time proof -> connection denied.
- Account linking without proof -> connection denied.
- Invalid Photon credentials -> connection denied.
- Banned user -> connection denied (via custom auth).
- Backend outage -> connection denied (fail closed).
- Legacy client -> connection denied (version check).

Authorization tests:
- Self-promotion -> server rejects (if UserData is client-writable, flag as vulnerability).
- Unauthorized access -> 403.
- Protected endpoints -> 401/403.
- Invalid token -> 401.
- Secret exposure -> none in client (verified by source code inspection, NOT by automated test).

Economy tests:
- Arbitrary currency grant -> server rejects (after fix).
- Insufficient balance purchase -> server rejects.
- Duplicate purchase -> idempotency prevents.
- Replayed redemption -> server rejects (worker validates code).
- Invalid receipt -> server rejects (if receipt validation implemented).
- Unowned cosmetic -> flag (after backend inventory check).

Multiplayer tests:
- Invalid RPC params -> flag/reject.
- RPC flood -> rate limit + flag.
- Invalid tag/infection -> flag.
- Client-controlled scene changes -> flag.
- Unowned cosmetic props -> flag.
- Master client changes -> log.
- Movement anomalies -> flag (heuristic).
- Telemetry limits -> flag.

Reliability tests:
- Worker outage -> fail closed for auth, fail open for gameplay.
- DB outage -> audit log delayed, core auth works.
- Quota exhaustion -> 429, fail closed.
- Auth service failure -> fail closed.
- Session revocation -> reject revoked sessions.
- Backup restore -> verify data integrity.
- Compromised admin session -> revoke + audit log.
- Monitoring/alerts -> verify alert delivery.

================================================================================
15b. Dashboard owner-only security
================================================================================

Closed registration: No public signup. Dashboard is private by default.

Initial owner enrollment: Secure out-of-band process (e.g., CLI command, invite link
with single-use token, or manual DB insert by developer). No self-service registration.
No ability to create another owner account from within the dashboard.

Backend authorization: Every sensitive API endpoint verifies identity and owner
permissions server-side. Deny-by-default. Direct API calls bypassing the frontend
are blocked (backend-enforced, not frontend-hidden).

MFA enforcement: TOTP required for all owner actions. Login rate limit: 5 attempts
per 15 minutes per IP. Account lockout after 10 failed attempts.

Session security: Short-lived access tokens (15 min) + refresh tokens (7 days,
rotating, revoked on logout). Secure cookie handling (SameSite=Strict, HttpOnly,
Secure). Session revocation on password change or MFA reset.

Secure recovery: Password reset via email (time-limited link). MFA reset requires
out-of-band verification (e.g., email + security question or admin approval).
No self-service owner creation or promotion.

CSRF protection: SameSite cookies + CSRF tokens for state-changing requests.
Not applicable if using Bearer token auth (no cookies).

Audit logging: All login attempts (success/failure), player lookups, moderation
actions, settings changes, rule changes, ban/unban actions logged with actor,
timestamp, IP, and reason.

Secret storage: All secrets in worker env vars (Cloudflare dashboard, encrypted
at rest). No privileged credentials in frontend JavaScript. No API keys in client.

Emergency access revocation: Owner can revoke all sessions, rotate JWT secret,
disable dashboard access. Process documented.

Additional staff roles: RBAC (Owner/Admin/Moderator/Viewer). Least privilege.
No role can escalate to Owner. Owner role cannot be assigned via dashboard.

Dashboard security test plan (all UNEXECUTED):
1. Unauthenticated API requests -> expect 401.
2. Registration attempts -> expect 404 (no registration endpoint).
3. Non-owner account -> expect 403 on all sensitive endpoints.
4. Direct API calls bypassing frontend -> expect 401/403 (backend-enforced).
5. Role escalation attempt -> expect 403 (server-side role check).
6. Owner creation attempt -> expect 403 (no endpoint exists).
7. Expired session -> expect 401.
8. Revoked session -> expect 401.
9. Stolen session token -> expect 401 (if token rotation/revocation implemented).
10. MFA bypass -> expect 403 (MFA required for all owner actions).
11. Login brute force -> expect 429 (rate limit).
12. CSRF (if cookie-based) -> expect 403 (CSRF token mismatch).
13. Account recovery abuse -> expect rate limit + verification.
14. Emergency session revocation -> verify all sessions invalidated.
15. Secret exposure in frontend -> verify no secrets in JS bundle (code inspection, NOT test).

All tests are PLANNED, not executed. No fabricated results.

================================================================================
16. Corrections made
================================================================================

1. Photon authentication (v03 correction): Worker does NOT validate Photon token via GetAccountInfo (GetAccountInfo verifies account existence, not token validity). Correct flow: Photon's custom auth URL receives Photon token. Worker delegates to PlayFab's /photon/authenticate endpoint for token validation. Worker then checks ban status via PlayFab (GetAccountInfo or ban list) using its own admin key. If no documented verification mechanism exists, custom Worker design is UNRESOLVED. Recommend PlayFab's standard /photon/authenticate endpoint. CORRECTED: earlier claim that client MUST send session ticket was wrong. PlayFab session ticket is NOT needed as custom auth param.

2. Heartbeat cost: 10s heartbeat = 8,640 req/player/day. At 100 CCU = 864,000 req/day (exceeds free tier). Revised to 30s request + 5-min D1 write. Or use KV for session state.

3. Meta Attestation: Token valid 24h by default (configurable). Server must validate exp (within 24h), nonce (one-time), timestamp (recent), app_integrity_state (StoreRecognized), package_cert_sha256_digest, device_integrity (Advanced/Basic). Rate limits: 100/hr, 200/day per device. security_update_pending_days only for Advanced/Basic. CORRECTED with official docs (previously docs were 404, now accessible).

4. Meta User Verification: getUserProof returns proof of account control. Server validates nonce (server-generated, one-time). DIFFERENT from App Attestation challenge_nonce. User Verification proves identity; App Attestation proves device/app integrity. CORRECTED (previously conflated). "Hardware-bound" wording corrected.

5. Currency grants: Reclassified as CONDITIONAL. PlayFab AddUserVirtualCurrency accepts client-specified amount (validates session, not amount). Whether clients can actually call it depends on PlayFab title settings. Keep server-authoritative as recommended design regardless.

6. Photon pricing: VERIFIED from official page. Free tier 20 CCU (dev only). 100 CCU = $95 one-time (12-month term). 500 CCU = $95/mo. 1000 CCU = $185/mo. 2000 CCU = $370/mo. Premium Cloud = $0.29/CCU, min $580/mo. Voice separate. PUN 2 is in maintenance/LTS mode.

7. Untested guarantees: Changed every untested security guarantee to conditional. Distinguish current (verified), proposed (designed), tested (executed). No test has been executed. All tests are planned.

8. Game-server hosting: Confirmed that "game-server hosting is already handled" refers to Photon Cloud (relay), NOT an authoritative dedicated server. Photon Cloud does not run game logic. No authoritative gameplay currently exists.

9. Dashboard owner-only: Added explicit closed-registration, owner-enrollment, backend authorization, MFA, rate limiting, CSRF, audit logging, secret storage, emergency revocation, and 15 unexecuted tests. (NEW)

10. Photon authentication (v03 correction): Worker does NOT validate Photon token via GetAccountInfo (GetAccountInfo verifies account existence, not token validity). Correct flow: Photon's custom auth URL receives Photon token. Worker delegates to PlayFab's /photon/authenticate endpoint for token validation. Worker then checks ban status via PlayFab (GetAccountInfo or ban list) using its own admin key. If no documented verification mechanism exists, custom Worker design is UNRESOLVED. Recommend PlayFab's standard /photon/authenticate endpoint.

What was NOT corrected (still valid):
- Tomahawk public site research (features, pricing, roles, integration methods).
- Local file research (getting started, API reference, portal docs, unity implementation, error codes).
- Ghidra binary analysis (native lib is thin wrapper + OpenSSL).
- Quest modification threat catalog (comprehensive, verified identities).
- Trust boundary analysis (client untrusted, backend trusted).
- Detection engine design (risk scoring, graduated response).
- Dashboard design (pages, auth, security).
- Cost estimates (revised with official pricing).

================================================================================
17. Unresolved questions
================================================================================

1. PlayFab UserData "Moderator" key: client-writable? (CRITICAL) - requires dashboard access.
2. CloudScript/Azure Functions deployed? (none in repo) - requires dashboard access.
3. PlayFab PurchaseItem validates price server-side? - requires dashboard/catalog config.
4. PlayFab bans enforced server-side? - requires dashboard access.
5. Meta attestation available to ScreechVR? - docs accessible, but eligibility/permissions unverified.
6. Photon custom auth configured? - requires dashboard access.
7. "Allow anonymous clients" disabled? - requires dashboard access.
8. Dev/prod app IDs separate? - requires dashboard access.
9. SpokesSigmaIAP receipt validation - requires reading script + catalog.
10. GDH leaderboard anti-cheat - requires inspecting GDH package.
11. ATM_TAB currency flow - requires reading ATM_TAB.cs + Atm_Manager.cs.
12. D1 write throughput sufficient - requires load test (k6).
13. Free tier limits sufficient - requires monitoring post-launch.
14. AppEntitlementCheck intended behavior - requires verification.
15. Meta User Verification SDK compatibility with Unity 2021.3.32f1 - requires testing.
16. Data retention policy preferences - requires user decision.
17. Budget ceiling and solo-dev time availability - requires user decision.
18. Evidence storage needs (telemetry vs screenshots/video) - requires user decision.
19. Existing server infrastructure: can it run trusted game logic? (Photon Cloud = relay only. No.)
20. Photon PUN 2 maintenance status: in LTS/maintenance mode. Photon recommends Fusion for new projects.
21. Photon token validation mechanism: can the Worker validate the Photon token independently, or must it delegate to PlayFab's /photon/authenticate? UNRESOLVED - requires PlayFab API documentation review.

================================================================================
18. Research activity log
================================================================================

Inspected during this pass:
- research/ (27 reports, README, FINAL_RESEARCH_SUMMARY)
- research/FINAL_SECURITY_ARCHITECTURE/ (26 deliverables)
- docs/screechvr-technical-map-2026-10-28.md
- docs/voideration-screechvr-architecture.md
- docs/voideration-anticheat-research.md
- docs/voideration-anticheat-review.md
- research/QUEST_MODIFICATION_THREAT_CATALOG.md
- SHARED-MEMORY.md, AGENTS.md
- Source files: Oculus_Login.cs, ScreechApi.cs, BuyCosmetic.cs, PhotonVRManager.cs (partial), Player.cs (partial), TagPlayer.cs, TagManager.cs, KickIfBanned.cs, AppEntitlementCheck.cs, UsernameValidator.cs, PlayerSpawner.cs, BestJumpscare.cs, GetCosmetics.cs, SecondaryCosmetics.cs, LevelSelect.cs, MapLoader.cs, Gamemode_System.cs, GamemodeManager.cs, Hand_Physic.cs

Official documentation fetched:
- Meta Quest Attestation API (https://developers.meta.com/vr/documentation/native/ps-attestation-api/) - FULLY ACCESSIBLE (2026-10-29)
- Photon pricing (https://www.photonengine.com/realtime/pricing) - FULLY ACCESSIBLE (2026-10-29)
- Photon custom authentication (https://doc.photonengine.com/pun/current/connection-and-authentication/authentication/overview-auth) - ACCESSIBLE
- OWASP API Security Top 10 2023 - ACCESSIBLE
- OWASP Cryptographic Storage Cheat Sheet - ACCESSIBLE
- Unity IL2CPP docs - ACCESSIBLE
- Unity AssetBundles docs - ACCESSIBLE

Documents created during this pass:
- research/SCREECHVR_SECURITY_REVIEW_v03_2026-10-29_1400.txt (this file)
- research/FINAL_SECURITY_CORRECTION/CORRECTION_INDEX.md (correction index)

Documents updated during this pass:
- research/FINAL_SECURITY_CORRECTION/CORRECTION_INDEX.md (new)

What was NOT done:
- No implementation code written.
- No project files modified.
- No services deployed.
- No dashboard access.
- No tests executed.
- No credentials reproduced.
- No production data changed.

================================================================================
19. Source register
================================================================================

Official documentation:
- Meta Quest Attestation API: https://developers.meta.com/vr/documentation/native/ps-attestation-api/ (ACCESSIBLE 2026-10-29)
- Meta User Verification: https://developers.meta.com/vr/documentation/spatial-sdk/ps-ownership/ (GATED - 404)
- PlayFab login best practices: https://learn.microsoft.com/gaming/playfab/identity/player-identity/login/login-basics-best-practices
- Photon PUN custom authentication: https://doc.photonengine.com/pun/current/connection-and-authentication/authentication/custom-authentication
- Photon PUN host migration: https://doc.photonengine.com/pun/current/gameplay/hostmigration
- Photon pricing: https://www.photonengine.com/realtime/pricing (ACCESSIBLE 2026-10-29)
- Cloudflare Workers pricing: https://developers.cloudflare.com/workers/platform/pricing/
- Cloudflare D1 limits: https://developers.cloudflare.com/d1/platform/limits/
- Cloudflare D1 pricing: https://developers.cloudflare.com/d1/platform/pricing/
- Cloudflare Durable Objects + WebSockets: https://developers.cloudflare.com/durable-objects/best-practices/websockets/
- Nakama authoritative multiplayer: https://heroiclabs.com/docs/nakama/concepts/multiplayer/authoritative/
- Unity upgrade guide: https://docs.unity.com/en-us/engine/7000.0/manual/upgrade-guides/upgrade-guide-unity63
- OWASP MASVS: https://mas.owasp.org/MASVS/
- OWASP API Security Top 10 2023: https://owasp.org/API-Security/editions/2023/en/0x11-t10/
- OWASP Cryptographic Storage Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html

Local research files:
- C:\Users\Void\Downloads\tomahawk stuff\ (all files, read-only)
- libTomahawkCore.so (5.3MB, SHA-256: 150710A0ED22048DDD3B18C49D7837EA60803B67DE768A6160DFF6A96ADD2B85)

Project files:
- E:\! Project Screech\! Screech VR\Screech VR\ (Unity project, read-only during research)

Confidence levels:
- Confirmed: verified against source code or official docs.
- Strong evidence: multiple sources agree, code partially verified.
- Plausible: reasonable inference, not verified.
- Historical: was true in the past, current status unknown.
- Unverified: cannot confirm, needs additional access/testing.

================================================================================
20. Final decision
================================================================================

Best free-first starting architecture:
Cloudflare Workers + D1 + KV + R2 (backend) + Cloudflare Pages (dashboard) + PlayFab (auth/inventory/bans) + Photon PUN 2 + Voice (networking). No dedicated game server for v1. No new providers. Extend existing infrastructure. Game-server hosting is "handled" but this is Photon Cloud (relay), not authoritative. No additional cost.

Best authentication model:
Meta User Verification (getUserProof, server-side) + PlayFab (persistent account) + Photon custom auth (room admission) + Voideration JWT (dashboard/API). Each token verified independently by its issuer. PlayFab session ticket is NOT needed as custom auth param. Worker validates Photon token via PlayFab's /photon/authenticate endpoint (or custom Worker that delegates to it). Worker uses its own PlayFab credentials for ban checks.

Best long-term anti-cheat architecture:
Server-authoritative where possible (currency, bans, cosmetics, version) + heuristic detection for movement + manual review + private dashboard. Accept that movement exploits can only be detected, not prevented, without dedicated server. Migrate to Photon Fusion or dedicated server (v2) only if cheating becomes serious. Game-server hosting is already handled but is relay-only; authoritative gameplay requires migration.

Five highest-priority vulnerabilities:
1. Client-trusted currency (AddCurrency local-first, PlayFab validates session not amount). CONDITIONAL on PlayFab title settings.
2. Client-trusted moderator status (PlayFab UserData "Moderator" key, likely client-writable). CONDITIONAL on PlayFab permissions.
3. Client-side ban enforcement (KickIfBanned polls every 5s, ignorable). FIX: Photon custom auth ban check.
4. No movement validation (speed/teleport exploits, heuristic detection only). DETECT ONLY.
5. Master client abuse (scene sync, room state manipulation). MINIMIZE AUTHORITY.

Key costs:
- Initial: $1-35/mo (Cloudflare free tier + domain).
- 100 CCU: $5-16/mo (Cloudflare) + $95/12mo (Photon, one-time).
- 500 CCU: $16-33/mo (Cloudflare) + $95/mo (Photon) = $111-128/mo.
- 1000 CCU: $16-40/mo (Cloudflare) + $185/mo (Photon) = $201-225/mo.
- Trade-off: engineering time (9-14 weeks MVP, 5-10h/week ops).

Explicit statement: Research is complete. No implementation performed. No project files modified. No services deployed. No production data changed. Awaiting explicit approval before any code is written.

================================================================================
END OF REPORT
================================================================================

Embed this paste

Install this app

  1. Tap the Share button
  2. Scroll down and tap "Add to Home Screen"
  3. Tap "Add" in the top right

Please confirm