Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@
**Vulnerability:** The `ImageLoader` and `VideoURLProvider` scripts validated and upgraded URLs to HTTPS in their string cache for comparisons, but failed to update the actual `VRCUrl` objects used for the download/playback requests. This meant the code *looked* secure (validating strings) but *acted* insecurely (requesting HTTP), creating a false sense of security and leaving users vulnerable to MITM attacks.
**Learning:** Validating a shadow copy (cache) of data does not secure the source data. When using object wrappers (like `VRCUrl`), modifying the extracted value does not modify the object itself. Security upgrades must be applied to the actual objects used for operations.
**Prevention:** Explicitly replace or upgrade the source objects (e.g., `predefinedUrls[i] = new VRCUrl(secureUrl)`) when sanitizing inputs, rather than just sanitizing the local variable used for logic checks.

## 2025-05-22 - Prevent Content Spoofing via Fallback Logic
**Vulnerability:** `FindMatchingUrlIndex` contained a fallback mechanism that blindly mapped unknown URLs from external lists to existing, unrelated `VRCUrl` slots when `useGeneratedUrlData` was enabled. This allowed external configuration to apply arbitrary captions to pre-approved images, creating a spoofing vulnerability.
**Learning:** Convenience features (like "auto-mapping" or "cyclic assignment" for unmatched items) often undermine strict allowlist enforcement. "Fail Closed" means if an exact match isn't found, the operation must fail, not guess.
**Prevention:** Remove fallback logic that bypasses exact matching. Ensure that lookups against an allowlist return an error or empty result if the specific item is not found.
13 changes: 0 additions & 13 deletions Scripts/ImageLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,19 +457,6 @@ private int FindMatchingUrlIndex(string urlToFind, int additionalCount = 0)
}
}

// If using generated data, we can use the cyclical assignment
if (useGeneratedUrlData)
{
// Use the next available predefined URL slot (cyclical)
int index = (_activeUrlIndices.Length + additionalCount) % urlCount;

// Ensure the predefined URL at this index exists
if (index < _predefinedUrlStrings.Length && _predefinedUrlStrings[index] != null)
{
return index;
}
}

// Last resort: find any available predefined URL
// REMOVED for security: preventing content spoofing.
// If the URL is not found in the predefined list, we should NOT display a random image.
Expand Down
29 changes: 0 additions & 29 deletions Scripts/VideoURLProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1040,35 +1040,6 @@ private int FindMatchingUrlIndex(string urlToFind, int additionalCount = 0)
}
}

// If using generated data, we can use the cyclical assignment
if (useGeneratedUrlData)
{
// Use the next available predefined URL slot (cyclical)
// Include additionalCount to account for items currently being batched
int index = (_activeUrlIndices.Length + additionalCount) % urlCount;

// Ensure the predefined URL at this index exists
if (index < _predefinedUrlStrings.Length && _predefinedUrlStrings[index] != null)
{
// Check if this URL is already used
string newUrl = _predefinedUrlStrings[index];
for (int j = 0; j < _activeUrlIndices.Length; j++)
{
int existingIndex = _activeUrlIndices[j];
if (existingIndex < _predefinedUrlStrings.Length && _predefinedUrlStrings[existingIndex] != null)
{
if (_predefinedUrlStrings[existingIndex] == newUrl)
{
Debug.Log($"[VideoURLProvider] URL already exists in playlist, skipping duplicate: {newUrl}");
return -1; // Skip adding duplicate
}
}
}

return index;
}
}

// Last resort: find any available predefined URL
// REMOVED for security: preventing content spoofing.
// If the URL is not found in the predefined list, we should NOT display a random video.
Expand Down