Skip to content

fix: Profile Share-Card Cache Collision: Incomplete Cache Key Causes Stale Card Served After Avatar/Bio Change#510

Open
prince-shakyaa wants to merge 2 commits into
GenAI-Security-Project:mainfrom
prince-shakyaa:fix/share-card-cache-key-collision
Open

fix: Profile Share-Card Cache Collision: Incomplete Cache Key Causes Stale Card Served After Avatar/Bio Change#510
prince-shakyaa wants to merge 2 commits into
GenAI-Security-Project:mainfrom
prince-shakyaa:fix/share-card-cache-key-collision

Conversation

@prince-shakyaa
Copy link
Copy Markdown

@prince-shakyaa prince-shakyaa commented May 22, 2026

Fix: Profile Share-Card Cache Collision (Fixes #508)

What This PR Does

Fixes an incomplete cache key in the profile share-card endpoint (/share/profile/{username}/card.png) that caused stale PNG cards to be served indefinitely after a user updated their avatar or bio — as long as their points, badges, and challenge counts remained unchanged.


Problem

The cache key was computed from only four fields:

# Before (share.py L287–289)
cache_data = (
    f"{username}:{total_points}:{len(earned_badges)}:{len(completed_progress)}"
)
cache_key = hashlib.md5(cache_data.encode()).hexdigest()

The fields avatar_type, avatar_url, avatar_emoji, and bio — all of which are visually prominent on the card — were excluded. This meant:

  • A user changing their avatar URL/emoji or bio would continue to receive the old cached card.
  • Any visitor sharing the card link on social media would see the stale version.
  • There was no way for a user to force-invalidate their own cached card without an admin manually deleting the cache file.

Fix

Include all visual identity fields in the cache key so that any profile change triggers a fresh render:

# After (share.py L287–292)
cache_data = (
    f"{username}:{total_points}:{len(earned_badges)}:{len(completed_progress)}"
    f":{profile.avatar_type or ''}:{profile.avatar_url or ''}:{profile.avatar_emoji or ''}"
    f":{profile.bio or ''}"
)
cache_key = hashlib.sha256(cache_data.encode()).hexdigest()

Note: Also upgraded the hash algorithm from MD5 to SHA-256. MD5 is not cryptographically safe and is flagged by modern security scanners. Since the cache key is derived from user-controlled values (avatar_url, bio), using SHA-256 is more appropriate and has negligible performance cost.


Files Changed

File Change
finbot/apps/ctf/routes/share.py Expand cache key to include avatar_type, avatar_url, avatar_emoji, bio; switch from MD5 to SHA-256
tests/unit/apps/ctf/test_share_card_cache_key.py 9 new unit tests covering all cache key scenarios

How to Test

  1. Sign in and claim a username (e.g. alice).
  2. Set avatar_type = "url" with any image URL and add a bio.
  3. Request GET /share/profile/alice/card.png — card is rendered and cached.
  4. Update the avatar URL or bio via the profile settings.
  5. Request GET /share/profile/alice/card.png again.
  6. Before this fix: old card is returned (stale cache hit).
  7. After this fix: new card is rendered correctly with the updated avatar/bio.

Tests

9 unit tests added in tests/unit/apps/ctf/test_share_card_cache_key.py:

Test ID What it covers
BUG-508-001 Confirms the original MD5 collision defect (documents the bug)
BUG-508-002 Cache key changes when avatar_url is updated
BUG-508-003 Cache key changes when avatar_emoji is updated
BUG-508-004 Cache key changes when avatar_type changes (e.g. urlgravatar)
BUG-508-005 Cache key changes when bio is updated
BUG-508-006 Cache key is stable when the profile is unchanged (no spurious re-renders)
BUG-508-007 Cache key still changes when score / completion counts change
BUG-508-008 Cache key is SHA-256 — guards against regression to MD5
BUG-508-009 None / empty optional fields handled gracefully — no crash

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Checklist


Related

Prince Shakya added 2 commits May 23, 2026 00:29
…elds

The cache key previously only included username, total_points, badges,
and challenge counts. This caused stale PNG cards to be served after
a user updated their avatar URL/emoji or bio without changing their score.

- Add avatar_type, avatar_url, avatar_emoji, and bio to the cache key
- Upgrade hash algorithm from MD5 to SHA-256

Fixes GenAI-Security-Project#508
…rity-Project#508)

9 tests covering:
- BUG-508-001: Confirms original MD5 collision defect
- BUG-508-002: Key changes on avatar_url update
- BUG-508-003: Key changes on avatar_emoji update
- BUG-508-004: Key changes on avatar_type update
- BUG-508-005: Key changes on bio update
- BUG-508-006: Key is stable when profile is unchanged
- BUG-508-007: Key still changes on score update
- BUG-508-008: Key uses SHA-256 (guards against MD5 regression)
- BUG-508-009: None/empty fields handled gracefully
@prince-shakyaa
Copy link
Copy Markdown
Author

Hii @saikishu , @e2hln
This PR fixes a bug where users' share-cards would stay stale even after they updated their avatar or bio. I expanded the cache key to include visual profile fields, upgraded the hash from MD5 to SHA-256 for better security, and added a full suite of unit tests to ensure it doesn't regress.
Let me know if you need any changes.
Thank You.

@joshlochner
Copy link
Copy Markdown
Contributor

joshlochner commented Jun 2, 2026

didn't test the unit test, but the bug fix lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Profile Share-Card Cache Collision: Incomplete Cache Key Causes Stale Card Served After Avatar/Bio Change

2 participants