Edge Shield (Cloudflare Worker)
Edge Shield is an MIT-licensed Cloudflare Worker that runs on your own Cloudflare account. It pulls the DugganUSA IP lane with your key, holds it in memory, and checks every request before it reaches your origin.
Source: github.com/pduggusa/dugganusa-edge-shield
What it does to a request
Section titled “What it does to a request”| Check | Response in block mode |
|---|---|
| Known scanner user agent or network (Shodan, Censys, LeakIX, Nuclei, ZMap and others) | 418 with a JSON body |
| Client IP matches the feed (single addresses and CIDR ranges, IPv4 and IPv6) | 403, header X-Blocked-Reason: ioc-match |
| Client IP over the per-minute rate limit | 429, header Retry-After: 60 |
Decoy path such as /.env or /wp-login.php (if honeypots are on) |
Decoy content |
| Anything else | Passed to your origin, with geo headers added |
SASE proxies (Zscaler, Netskope, Prisma and similar) are never treated as scanners.
Requests forwarded to your origin carry added request headers: X-CF-City, X-CF-Region, X-CF-Latitude, X-CF-Longitude, X-CF-Timezone, X-CF-Metro-Code, X-CF-Postal-Code and X-CF-ASN-Org when Cloudflare knows them, plus X-DugganUSA-Shield: active and X-DugganUSA-IOCs (the number of indicators currently loaded).
Before you start
Section titled “Before you start”- A Cloudflare zone, with the DNS records you want protected proxied (orange cloud). The Worker never sees traffic to an unproxied record.
- Node.js and
npx wrangler(Wrangler 4), logged in withnpx wrangler login. - A DugganUSA API key. Register free at analytics.dugganusa.com/stix/register.
Deploy
Section titled “Deploy”git clone https://github.com/pduggusa/dugganusa-edge-shield.gitcd dugganusa-edge-shieldcp wrangler.example.toml wrangler.local.tomlEdit wrangler.local.toml:
-
Replace the route placeholder with one catch-all route per host you want protected:
routes = [{ pattern = "www.example.com/*", zone_name = "example.com" },] -
Review the
[vars]block (see Configuration). The example ships inobservemode with honeypots and hit reporting off.
Do not deploy the repository’s wrangler.toml. It is DugganUSA’s own deployment, with our routes and account.
Set the key as a Worker secret. Wrangler prompts for the value, so it never appears in a file, your shell history or the repository:
npx wrangler secret put DUGGANUSA_API_KEY -c wrangler.local.tomlCheck the build, then deploy:
npx wrangler deploy --dry-run -c wrangler.local.tomlnpx wrangler deploy -c wrangler.local.tomlwrangler.local.toml is in .gitignore.
Verify
Section titled “Verify”The repository includes a probe script (bash and curl only). It exits non-zero when a check fails.
scripts/verify.sh --product www.example.com --mode observe- In
blockmode, a scanner user agent gets418and the response carriesX-Powered-By: DugganUSA Edge Shield. - In
observemode, the same request is let through and the response carriesX-DugganUSA-Observed: scanner. - In both modes, a normal browser user agent gets
200(a redirect also passes).
Add --sensor host.example.com for any host that must not be shielded; the script checks that no shield header appears there.
Workers Logs ([observability] enabled = true in the example config) show refresh results. A failed feed pull logs IOC refresh FAILED: ips.csv <status>, domains.csv <status>.
Configuration
Section titled “Configuration”Every setting is a [vars] entry. A value the Worker cannot parse falls back to the default and logs a config: warning, so a typo never loosens your posture silently.
| Variable | Default | Example config | Meaning |
|---|---|---|---|
SHIELD_MODE |
block |
observe |
block enforces. observe lets everything through and records what it would have blocked (Workers Logs line plus an X-DugganUSA-Observed response header). Covers scanner 418, IOC 403 and rate-limit 429; not honeypots |
IOC_BLOCKING |
true |
true |
Block feed-listed IPs. false also stops feed downloads |
IOC_MIN_CONFIDENCE |
80 |
80 |
Load only indicators at or above this confidence (0 to 100) |
IOC_FEED_DAYS |
7 |
7 |
Feed lookback window in days (1 to 90) |
IOC_REFRESH_MINUTES |
60 |
360 |
Minutes between feed refreshes (5 to 1440). See Quota |
SCANNER_418 |
true |
true |
Answer known scanners with 418 |
RL_ANON |
100 |
100 |
Requests per minute per IP without an Authorization header or ?api_key=. 0 disables |
RL_AUTH |
500 |
500 |
Requests per minute per IP that present one. 0 disables |
HONEYPOTS_ENABLED |
true |
false |
Serve decoy content on canary paths. See Privacy |
APPLIANCE_CANARIES |
unset | unset | NetScaler Gateway decoys (/vpn/, /logon/LogonPoint/, /cgi/login and similar). Off on your zones unless you set true. Leave it off if a real NetScaler sits behind the host |
HARVESTED_OBSERVE |
unset | unset | Pass through requests on paths taken from public exploit proofs of concept, and report them. Off on your zones unless you set true |
FEED_HIT_REPORTING |
true |
false |
Report feed matches back to DugganUSA. See Privacy |
SCHEMA_INJECT_HOSTS |
DugganUSA’s hosts | empty | Hosts that get DugganUSA’s own Organization JSON-LD. Leave empty on your site |
SENSOR_HOSTS |
none | empty | Hosts passed straight to origin, untouched. Exact hosts or *.example.com, comma-separated. Use for honeypots and telemetry hosts, in addition to giving them no route |
PATH_ORIGINS |
none | unset | Optional. Serve chosen paths from another origin after the shield has run, as host/prefix=>https://origin/prefix, comma-separated. GET and HEAD only. The target host must be listed in ORIGIN_EDGE_HOSTS |
IOC_MIN_CONFIDENCE and IOC_FEED_DAYS are passed to the feed as min_confidence and days. Blocking uses the IP lane, which honors both; see CSV blocklists.
Secrets
Section titled “Secrets”| Secret | Required | Meaning |
|---|---|---|
DUGGANUSA_API_KEY |
Yes | Your DugganUSA key. Without it the Worker skips feed downloads and blocks no feed IPs |
ORIGIN_EDGE_SECRET |
No | Leave unset. When set, the Worker adds x-dugganusa-edge: <secret> to requests it forwards to the hosts in ORIGIN_EDGE_HOSTS, so that origin can confirm a request came through the edge before trusting cf-connecting-ip. If you want this for your own origin, set both, compare the header in constant time at the origin, and only then trust the client IP header |
Any copy of x-dugganusa-edge sent by a client is stripped before forwarding.
Each refresh pulls two feed lanes (ips.csv and domains.csv), so it costs 2 queries, and each Cloudflare data center that serves your traffic refreshes on its own schedule. Inside a data center the pull is shared, and refreshes closer together than 10 minutes reuse the cached copy.
| Key | Suggested IOC_REFRESH_MINUTES |
Queries per day, per data center |
|---|---|---|
| Free (10 per day) | 360 |
8 |
| Shield (300 per day) or above | 60 |
48 |
With the default of 60 minutes, a Free key runs out of quota early in the day and the Worker keeps blocking on whatever list it last loaded, or on an empty list if no pull succeeded. The example config ships 360 for this reason. Plans and limits: Plans.
Privacy
Section titled “Privacy”The Worker runs on your Cloudflare account. For ordinary traffic, including requests it blocks, DugganUSA sees only your key’s feed pulls.
Two optional features send data to DugganUSA:
- Honeypot canaries (
HONEYPOTS_ENABLED). A request to a decoy path sends the visitor’s IP address, full User-Agent, city, region, country, ASN and organization, the full request URL, method and TLS version. That is personal data under GDPR; put a data processing agreement in place or keep this off. The decoy paths (for example/graphql,/webmail/*, anything containing.env) answer with deception content instead of your real response, so turn this off or editCANARY_PATHSinsrc/worker.jsif any of them is a real route on your site. - Feed hit reporting (
FEED_HIT_REPORTING). When a feed indicator matches, the Worker reports the indicator that matched, the action (blockedorobserved), a count and the Cloudflare ray ID, authenticated with your key. It does not send the visitor’s identity, your hostname or the URL. When the match came from a CIDR range, the reported address may be one DugganUSA never published individually: it is the address that matched the range you chose to block.
Harvested-path observation (HARVESTED_OBSERVE), if you opt in, reports the CVE, the matched path from our list, ASN, country and method; never your hostname, the visitor’s User-Agent or network.
Upgrading
Section titled “Upgrading”git pullnpx wrangler deploy --dry-run -c wrangler.local.tomlnpx wrangler deploy -c wrangler.local.tomlYour wrangler.local.toml and secrets are untouched by a pull. Read CHANGELOG.md in the repository before upgrading; new options default to the previous behavior unless the changelog says otherwise.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check |
|---|---|
verify.sh fails: a scanner user agent is not answered with 418 |
The DNS record is proxied, and the route pattern matches the host. If another Worker has a more specific route on the same host, that one runs instead |
Your origin sees X-DugganUSA-IOCs: 0 |
Workers Logs for IOC refresh FAILED. A 401 means the secret is missing or wrong; 429 means the key’s daily quota is used up |
Legitimate clients get 429 |
Raise RL_ANON or RL_AUTH, or set the affected tier to 0 |
| Something you expected to be blocked is let through | SHIELD_MODE is still observe, or the address is below IOC_MIN_CONFIDENCE |
The repository’s TROUBLESHOOTING.md covers more cases.