Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Gravatar hash is computed from the un-lowercased email, so mixed-case accounts render an identicon

Open Beginner friendly
#1,604 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
go, typescript
Domain
backend

Research direction

Start in pkg/gravatar/gravatar.go at GetAvatarURL and compare its input handling with the lowercasing and trimming already used in ui/src/pages/Users/Settings/Profile/index.tsx. Verify the generated URL uses the normalized email so mixed-case stored addresses resolve the registered Gravatar instead of the identicon fallback.

Written by the indexing model from the issue text.

Description

Describe the bug

pkg/gravatar.GetAvatarURL hashes the email address without lowercasing it:

// pkg/gravatar/gravatar.go
func GetAvatarURL(baseURL, email string) string {
	hasher := sha256.Sum256([]byte(strings.TrimSpace(email)))
	hash := hex.EncodeToString(hasher[:])
	return baseURL + hash
}

The Gravatar specification requires the address to be trimmed and lowercased
before hashing, so any account whose stored address contains an uppercase letter
hashes to an address Gravatar does not know. The user's avatar is never found and
the identicon fallback (&d=identicon, added by the UI) is rendered instead.

Two details make this hard to work around from outside:

  1. selectedAvatar in internal/service/siteinfo_common/siteinfo_service.go
    recomputes the Gravatar URL from the stored address on every response, for
    both default_avatar: gravatar and an explicit per-user avatar.type: gravatar. Selecting "Gravatar" in Settings → Profile stores the correct URL
    (the UI hashes correctly, see below) but the server overwrites it on read.
  2. Nothing in the backend normalises a stored address. grep -rn ToLower internal/ | grep -i mail returns nothing, and the external-login path copies
    the provider's address verbatim
    (internal/service/user_external_login/user_external_login_service.go:258,
    userInfo.EMail = externalUserInfo.Email). With an OIDC/OAuth2 connector the
    casing is whatever the identity provider sends, so accounts are created
    mis-cased without any user or admin action.

The web UI already does this correctly, which is why the bug is easy to miss —
ui/src/pages/Users/Settings/Profile/index.tsx:

const str = res.e_mail.toLowerCase().trim();
const hash = sha256(str);

So the avatar preview in Settings → Profile shows the user's real Gravatar while
every other surface (question lists, answers, comments, user cards) shows an
identicon. Frontend and backend disagree on the hash for the same account.

To Reproduce

  1. Admin → Settings → Users: set "Default avatar" to Gravatar.

  2. Create a user whose email address contains an uppercase letter, e.g.
    Example.User@example.com, and register that lowercase address at
    gravatar.com with an avatar image.

  3. Open any page listing that user (or their profile).

  4. An identicon is rendered instead of the Gravatar avatar.

  5. Confirm the cause without Answer:

    $ printf '%s' 'example.user@example.com' | shasum -a 256   # what Gravatar expects
    $ printf '%s' 'Example.User@example.com' | shasum -a 256   # what Answer sends
    

    Requesting https://www.gravatar.com/avatar/<hash>?d=404 returns 200 for the
    first hash and 404 for the second.

  6. Settings → Profile shows the correct avatar in its preview, because the UI
    lowercases before hashing.

Expected behavior

GetAvatarURL lowercases the address before hashing, matching the Gravatar
specification and the existing frontend behaviour, so a registered Gravatar is
found regardless of the casing of the stored address.

Screenshots

n/a — the hash comparison in step 5 shows the failure directly.

Platform

  • Device: Desktop
  • OS: Linux (container), macOS client
  • Browser and version: Chrome (any)
  • Version: v2.0.2
Dominant language
Go
Stars
15.7k
Forks
1.4k
Avg merge
1d 20h
Merged PRs (30d)
6

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from apache/answer

All issues in apache/answer

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.