A curated list of AI tools and resources for developers, see the AI Resources .

In Depth Look at GitHub Funding Phishing Scams: Profit Chain & Defense Strategies

Explore the GitHub funding phishing scam, its attack process, and defense strategies to protect against Web3 threats in this in-depth analysis.

This article uses my personal experience with the “GitHub × Gitcoin Developer Fund 2025” phishing incident to systematically break down the profit chain, attack process, technical implementation, and defense strategies, helping the tech community identify and respond to new Web3 scams.

Introduction

Recently, I received an email on GitHub disguised as a “GitHub × Gitcoin Developer Fund 2025” notification, claiming I was “eligible” and only needed to click a link, verify my wallet via Gitcoin Passport, and pay a “refundable deposit” to receive funding. Many developers have reported similar emails; see Community Discussion #174283 .

Figure 1: Phishing Email Screenshot
Figure 1: Phishing Email Screenshot

This scam exploits the authority of GitHub’s notification system, combines Web3 wallet authorization and deposits, and masquerades as a prestigious funding program—while in reality, it’s a scheme to steal funds and accounts. This article analyzes the profit motives, attack chain, technical details, and defense measures.

GitHub Notification “Shell” and Phishing Entry Point

Attackers use scripted accounts to create Issues or Discussions in unfamiliar repositories and @-mention thousands of developers (including myself), triggering GitHub’s system notification emails. This easily bypasses spam filters and lands directly in inboxes. Even experienced developers may let their guard down due to the “official GitHub notification” format.

Example link: Phishing Issue (GitHub Issue, safe to click)

Phishing Page Analysis and Typical Features

Visiting the phishing site github-foundation.com, any click on the page triggers a “Connect Wallet” popup, supporting MetaMask, Trust Wallet, WalletConnect, and other mainstream wallets.

Figure 2: Fake Gitcoin Page
Figure 2: Fake Gitcoin Page

Key features include:

  • Domain Spoofing: github-foundation.com is completely different from the official domain.
  • Full-screen Inducement: The page contains no real information; all actions lead to wallet connection.
  • Fake Endorsements: Displays real Gitcoin data but out of context.
  • Wallet Trap: After authorization or deposit, funds and permissions are stolen.

Target Profile and Attack Strategy

Attackers prioritize developer accounts with influence and assets, such as GitHub Developer Program members, those with Sponsors, or high activity. These accounts are more likely to click the link and have higher-value wallets and repository permissions.

At the same time, attackers use a wide-net strategy, mixing high- and low-value users. Even a few victims yield profit.

Profit Chain and Attack Process

The complete profit chain is as follows:

  • Traffic Acquisition: Mass account posting, @-mentioning users, leveraging GitHub email notifications.
  • Conversion Design: Fake domains, copy, and partners to create an “official” feel.
  • Profit Methods: Deposit payments, unlimited wallet authorization to steal assets, GitHub authorization for supply chain attacks.
  • Risk Hedging: Disposable accounts, mass deployment, quick exit.
Figure 3: Attack Flowchart
Figure 3: Attack Flowchart

Technical Implementation and Engineering Details

  • Exploits GitHub notification system to increase delivery success.
  • Typosquatting domains mimicking github.com.
  • Social engineering via wallet interaction, using “just signature, no charge” to lower defenses.
  • Mass @-mentions for wide coverage and low attack cost.
  • Subsequent GitHub authorization may inject malicious code.

Community Feedback and Victim Reports

In the GitHub Community discussion area, developers have reported similar spam, indicating the scam is spreading widely and is not an isolated case.

How to Delete the Spam Notifications

For cleaning up spam or “phantom” notifications caused by this type of phishing, refer to the effective solution in the community discussion . Download the cleanup script below and run it locally with node remove_phantom_notifications.js TIMESTAMP:

🟨 remove_phantom_notifications.js
  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
const { exec } = require("node:child_process");
const { basename } = require("node:path");

function runShellCommand(command) {
  return new Promise((resolve, reject) => {
    exec(command, (error, stdout, stderr) => {
      if (error) {
        reject({ error, stderr });
        return;
      }
      resolve(stdout);
    });
  });
}

let _githubToken = null;
async function getGithubToken() {
  if (!_githubToken) {
    _githubToken = await runShellCommand("gh auth token");
  }
  return _githubToken;
}

async function getNotifications(since) {
  const response = await fetch(`https://api.github.com/notifications?all=true&since=${since}`, {
    headers: {
      'Accept': 'application/vnd.github+json',
      'Authorization': `Bearer ${await getGithubToken()}`,
      'X-GitHub-Api-Version': '2022-11-28',
    },
  });
  return response.json();
}

async function shouldIncludeNotificationForRemoval(notification) {
  try {
    const response = await fetch(`https://api.github.com/repos/${notification.repository.full_name}`, {
      headers: {
        Accept: "application/vnd.github+json",
        Authorization: `Bearer ${await getGithubToken()}`,
        "X-GitHub-Api-Version": "2022-11-28",
      },
    });
    return response.status === 404;
  } catch (error) {
    console.log("threw");
    if (error.code && error.code === 404) {
      return true;
    }
    console.error(error);
    throw error;
  }
}

async function markNotificationRead(notification) {
  const response = await fetch(notification.url, {
    method: "PATCH",
    headers: {
      "Authorization": `Bearer ${await getGithubToken()}`,
      "Accept": "application/vnd.github+json",
      "X-GitHub-Api-Version": "2022-11-28",
    },
  });
  if (!response.ok) {
    console.error(`Failed to mark notification with thread URL ${notification.url} from repo ${notification.repository.full_name} as read: ${response.status} ${response.statusText}`);
  }
}
async function markNotificationDone(notification) {
  const response = await fetch(notification.url, {
    method: "DELETE",
    headers: {
      "Authorization": `Bearer ${await getGithubToken()}`,
      "Accept": "application/vnd.github+json",
      "X-GitHub-Api-Version": "2022-11-28",
    },
  });
  if (!response.ok) {
    console.error(`Failed to mark notification with thread URL ${notification.url} from repo ${notification.repository.full_name} as done: ${response.status} ${response.statusText}`);
  }
}

async function unsubscribe(notification) {
  const response = await fetch(notification.subscription_url, {
    method: "DELETE",
    headers: {
      "Authorization": `Bearer ${await getGithubToken()}`,
      "Accept": "application/vnd.github+json",
      "X-GitHub-Api-Version": "2022-11-28",
    },
  });
  if (!response.ok) {
    console.error(`Failed to unsubscribe from notification with thread URL ${notification.url} from repo ${notification.repository.full_name}: ${response.status} ${response.statusText}`);
  }
}

async function main() {
  const since = process.argv[2];
  if (!since) {
    console.error(`Usage: ${basename(process.argv[0])} ${basename(process.argv[1])} <since>`);
    process.exit(1);
  }

  try {
    new Date(since);
  } catch (error) {
    console.error(`${since} is not a valid ISO 8601 date. Must be formatted as YYYY-MM-DDTHH:MM:SSZ.`);
    console.error(`Usage: ${basename(process.argv[0])} ${basename(process.argv[1])} <since>`);
    process.exit(1);
  }

  const notifications = await getNotifications(since);
  for (const notification of notifications) {
    if (await shouldIncludeNotificationForRemoval(notification)) {
      console.log(`Marking notification with thread URL ${notification.url} read from repo ${notification.repository.full_name}`);
      await markNotificationRead(notification);
      console.log(`Marking notification with thread URL ${notification.url} done from repo ${notification.repository.full_name}`);
      await markNotificationDone(notification);
      console.log(`Unsubscribing from notification with thread URL ${notification.url} from repo ${notification.repository.full_name}`);
      await unsubscribe(notification);
    }
  }
  console.log("Done");
}

main().catch(console.error);

For example, to clean phantom notifications after September 25, 2025:

node remove_phantom_notifications.js 2025-09-25T00:00:00Z

Defense and Emergency Measures

Here are some defense strategies:

  • Personal Defense:
    • Treat any wallet signature or deposit request as suspicious; assume a scam by default.
    • Enable GitHub 2FA and regularly audit OAuth Apps, PATs, SSH Keys; revoke anything suspicious.
    • Use email filters to auto-label notifications with keywords like Gitcoin, Fund, Passport, or USDC.
  • Organization Defense:
    • Enforce SSO and least privilege access.
    • Restrict external app authorizations and unify official funding entry points.
    • Prepare rapid emergency plans for key revocation and repository isolation.
  • Post-Incident Actions:
    • Revoke wallet authorizations.
    • Delete suspicious GitHub authorizations, tokens, and SSH keys.
    • Audit repository secrets and GitHub Actions.
    • Report phishing domains, accounts, and repositories.

IOC Appendix (Indicators of Compromise)

  • Phishing Domain: github-foundation.com
  • Common Keywords: GitHub × Gitcoin Developer Fund 2025, refundable deposit, Gitcoin Passport verification
  • GitHub Behavior: Mass unfamiliar accounts posting Issues/Discussions, @-mentioning hundreds of unrelated developers.

Summary

This case reveals a new type of phishing scam at the intersection of open source and Web3. Attackers exploit GitHub’s notification mechanism, combine wallet authorization and deposit monetization, and leverage large-scale engineering and platform endorsement. Effective defense requires zero trust for funds and authorizations, always using official entry points, and both individuals and organizations should implement least privilege principles and raise security awareness.

Post Navigation

Comments