GitHub User Email should be Private
More Info:
Checks that the primary email addresses associated with a GitHub account is set to private visibility. Email addresses added to GitHub should be set to private visibility to increase privacy and prevent account reconnaissance.
Risk Level
Medium
Address
Security
Compliance Standards
- Cloudanix Best Practice
Triage and Remediation
- Remediation
Remediation
Using Console
To make a GitHub user’s email private using the GitHub web console:
-
Sign in to GitHub
Log into the GitHub account whose email you want to make private. -
Open User Settings
- Click your profile picture (top-right corner).
- Click “Settings” in the dropdown.
-
Go to Email Settings
- In the left-hand menu, click “Emails”.
-
Hide your email address from public profile
Under “Primary email address” / “Email privacy”:- Check “Keep my email addresses private”.
- If available, also check “Block command line pushes that expose my email” to prevent your real email from appearing in commits.
-
Use GitHub-provided noreply email (recommended)
- Still under “Emails”, note the
@users.noreply.github.comaddress. - Optionally set it as your primary email if you want all GitHub operations to use this masked address where possible.
- Still under “Emails”, note the
-
Confirm profile visibility
- Go to Settings → Profile.
- Ensure the Email field is either empty or shows the noreply address, not your real email.
If this is for an organization policy, you cannot centrally force all members’ email addresses to be private via IAM alone; each user must perform the above steps on their own account. You can, however, document this as a security requirement and verify via profile checks or audits.
Using CLI
For GitHub, “making user email private” has two parts:
- Avoid exposing your real email in commits (git config)
- Use GitHub’s noreply email (per-user setting + git config)
GitHub does not currently expose the “Keep my email address private” toggle as a GitHub CLI command, but you can fully remediate exposure in Git and use gh to automate the rest.
1. Get your GitHub noreply email (with gh)
gh api user/emails --method GET --jq '.[] | select(.primary == true and .visibility == "public") | .email'
If you use email privacy, your primary public email will be something like:
12345678+username@users.noreply.github.com
If that doesn’t return the noreply, list all emails and pick the noreply one:
gh api user/emails --method GET --jq '.[].email'
2. Set noreply email as your global Git identity
Replace <NOREPLY_EMAIL> with the value from above:
git config --global user.email "<NOREPLY_EMAIL>"
git config --global user.name "<YOUR_NAME>"
For a single repo only:
cd /path/to/repo
git config user.email "<NOREPLY_EMAIL>"
git config user.name "<YOUR_NAME>"
This prevents future commits from exposing your real email.
3. Block pushes that expose real email (per‑repo policy)
You can script a guard using gh + git hooks.
Create .git/hooks/pre-push:
#!/usr/bin/env bash
REAL_EMAIL_PATTERN='@gmail\.com\|@outlook\.com\|@yourcompany\.com' # adjust
if git log --format='%ae' origin/main..HEAD 2>/dev/null | grep -E "$REAL_EMAIL_PATTERN" ; then
echo "Push blocked: commits contain real email addresses. Use your GitHub noreply email."
exit 1
fi
Make it executable:
chmod +x .git/hooks/pre-push
You can distribute this with:
gh repo clone <owner>/<repo>
# then commit the hook logic in a script and tell users to install it, or manage via internal tooling
4. (Required via Web UI once per user) Turn on email privacy and blocking
This part cannot be fully done via gh today; it’s a one‑time user action:
- GitHub → Settings → Emails
- Check “Keep my email address private”
- Check “Block command line pushes that expose my email”
After you do that once, the CLI + git config setup above will ensure ongoing compliance.
Summary (CLI-focused “remediation”)
- Use
gh apito discover your noreply email. - Use
git config(scriptable and enforceable in your org) to set that asuser.email. - Optionally add
pre-pushhooks (distributed viagh repoflows) to block pushes that contain real emails.
Using Python
Below are concrete steps and a Python example to remediate “User Email should be Private” for GitHub by removing (or replacing) the public email via the GitHub API.
Important limitation:
GitHub does not let an org admin change a member’s profile email. Each user must do this themself using their own personal access token (PAT). The script below is meant to be run per user (or with that user’s token).
1. Decide the desired state
You typically want no real email shown on the public profile. Two common options:
-
Clear the public email (best for privacy):
- Set
emailtonull(or omit it) so the profile doesn’t show a public email.
- Set
-
Replace with GitHub’s noreply email:
- Format:
<id>+<username>@users.noreply.github.com - This is still an email but not a real one.
- Format:
If your scanner says “User Email should be Private,” either clearing it or switching to noreply will usually satisfy the requirement.
2. Get a GitHub Personal Access Token (PAT)
For each user:
- Go to Settings → Developer settings → Personal access tokens → Tokens (classic).
- Create a token with:
- Scope:
user(this is needed to update the profile).
- Scope:
- Copy the token (you’ll use it in the script as
GITHUB_TOKEN).
3. Python code to clear or replace public email
Option A: Clear public email
import os
import requests
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") # or hardcode for testing
if not GITHUB_TOKEN:
raise SystemExit("Set GITHUB_TOKEN in the environment.")
API_URL = "https://api.github.com/user"
headers = {
"Authorization": f"token {GITHUB_TOKEN}",
"Accept": "application/vnd.github+json",
}
# Get current user profile to show what will be changed (optional)
resp = requests.get(API_URL, headers=headers)
resp.raise_for_status()
user = resp.json()
print(f"Current login: {user['login']}, public email: {user.get('email')}")
# PATCH to clear the public email by setting it to null
payload = {
"email": None
}
resp = requests.patch(API_URL, headers=headers, json=payload)
resp.raise_for_status()
# Confirm
resp = requests.get(API_URL, headers=headers)
resp.raise_for_status()
updated = resp.json()
print(f"Updated public email: {updated.get('email')}")
Option B: Set to GitHub noreply email
import os
import requests
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
if not GITHUB_TOKEN:
raise SystemExit("Set GITHUB_TOKEN in the environment.")
API_URL = "https://api.github.com/user"
headers = {
"Authorization": f"token {GITHUB_TOKEN}",
"Accept": "application/vnd.github+json",
}
# Get current user to build noreply address
resp = requests.get(API_URL, headers=headers)
resp.raise_for_status()
user = resp.json()
user_id = user["id"]
username = user["login"]
noreply_email = f"{user_id}+{username}@users.noreply.github.com"
print(f"Setting public email to noreply: {noreply_email}")
payload = {
"email": noreply_email
}
resp = requests.patch(API_URL, headers=headers, json=payload)
resp.raise_for_status()
# Confirm
resp = requests.get(API_URL, headers=headers)
resp.raise_for_status()
updated = resp.json()
print(f"Updated public email: {updated.get('email')}")
4. (Optional) Enforce noreply in Git commits
Even if the profile email is private, commits can still leak real emails. Each user should:
- Set global Git config to noreply:
git config --global user.email "<id>+<username>@users.noreply.github.com"
- In GitHub UI: Settings → Emails →
- Check “Keep my email addresses private”
- Check “Block command line pushes that expose my email” (if available)
This must be done per user; there is no GitHub API for those checkboxes right now.
If you tell me how your scanner checks this (e.g., via GitHub API or UI), I can adjust the payload/logic to match that exact rule.
Using Terraform
Terraform cannot remediate this finding: the GitHub provider does not expose any resource or argument to manage a user’s primary email or its visibility setting.
You must change this at the account level, either:
- Via GitHub UI:
Profile → Settings → Emails → set your primary email to “Keep my email addresses private”.
or
- Via GitHub API (as per the docs you linked), authenticated as the user, e.g.:
GET /user/emailsto list emails and find the primary one.PATCH /user/email/visibilitywith{"visibility": "private"}to toggle the primary email’s visibility.