* Say where this repository actually is
On 2026-04-21 a commit pointed repository, homepage and bugs at our Gitea
instance — "migrate git dependencies to Gitea mirror". Nothing else moved.
origin is still GitHub, the published @pezkuwi/phishing still says GitHub, and
git.pezkuwichain.io/pezkuwichain/phishing answers 500, so everyone who installs
the package has been given a dead homepage and a dead bug tracker.
It also broke the Master build on 2026-09-13, when the toolchain began reading
the field. @pezkuwi/dev, which is ours, does this:
const repoPath = pkg.repository.url
.split('https://github.com/')[1]
.split('.git')[0];
A URL from any other host makes [1] undefined and the build dies with "Cannot
read properties of undefined (reading 'split')" — a message that names neither
the field nor the file. Three runs failed that way and master has had no green
build since.
The metadata now says what is true today. This is not a decision about where
the project should live: it is an alignment with where the code already is and
with what we already publish.
That migration is still worth finishing, and this is the sequencing it needs.
Moving the repository to Gitea for real means fixing @pezkuwi/dev first, so a
toolchain built for a state that hosts its own git stops assuming github.com.
scripts/checkRepoMeta.mjs is the tripwire: it fails the metadata here rather
than letting it surface as an unreadable stack trace or ship as a dead link.
The check runs in the Lists workflow, which has no toolchain to install and so
still runs when the build does not. Nails: restoring the April commit turns
three cases red, migrating only half the repository turns two red, and leaving
homepage behind on the old host turns one red.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Hold the new check to the repository's own lint rules
The file I added failed all seven of them and lint had been green: the licence
header every file here carries, import order, an optional chain, object keys in
ascending order and an argument on its own line. Verified with eslint run the
way CI runs it, without --fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pezkuwi/phishing
A curated list of potentially less-than-honest sites inclusive of a simple JS utility function to check any host against this list.
How the lists are kept
These lists are Pezkuwi's copy of polkadot-js/phishing: they follow upstream, with a few entries of our own.
- Daily sync.
sync-upstream.ymltakes upstream's lists every day, layspezkuwi/overlay.jsonover them, and commits the result tomaster. On a day out of bounds it writes nothing and opens an issue instead: more than 25 sites unblocked or 5000 added, more than 10 scam addresses dropped, one of our own domains blocked, or one of our entries lost (scripts/lists.mjs). - Our entries.
overlay.jsonholds the sites we block that upstream does not (deny), upstream entries we deliberately do not block (undeny), and our own domains, which no entry may ever block (protect). Each entry records why and since when. Change our entries there, not inall.json, which every sync rewrites from upstream. - Publishing. phishing.pezkuwichain.io pulls
masterevery hour and checks the lists again before it serves them (pezkuwi/host/). - Checks.
lists.ymlruns the rules' tests andscripts/checkLists.mjson every change. Neither needs the build toolchain.
Additions
Report a new site or scam address to polkadot-js/phishing, and the daily sync brings it here. A site that targets Pezkuwi specifically, and that upstream would not list, goes in the deny section of pezkuwi/overlay.json, with its reason and date.
Availability
Changes reach phishing.pezkuwichain.io/all.json and phishing.pezkuwichain.io/address.json within the hour after they land on master. These can be consumed via @pezkuwi/phishing and other tools capable of parsing JSON.
Notable users
The following wallets integrate either address or site blocking from these lists:
Integration
Since the lists are published as JSON, integration for any non-JS wallets (only a JS library that is provided) should be simple - retrieve the applicable list, parse the JSON, and do the required checks either on the host or address as per the requirements. The Javascript library does have some features that may be worth thinking about for other integrations -
- instead of retrieving the list each time a request is made, a local copy is cached for 45 minutes and then re-retrieved when the timer expires (as a request is made)
- for address checks, the check is done on the decoded ss58 address to ensure that network-jumps with the same keys are avoided (so addresses do not have to be re-added for other networks, a single entry will cover all)
Contributing
These lists are intended to be maintained with active input from the community, so contributions are welcome, either via a pull request (edit above as described in additions) or by logging an issue.