WEDOS ProtectionENISA — European Union Agency for CybersecurityEUPrepared for ENISA · 100% European
TLP:AMBER  ·  Sharing limited to ENISA and WEDOS. Do not distribute beyond the approved circle.
WGP · v1.2.0 TLP:AMBER CONFIDENTIAL DRAFT 2026-06-28

Portal protection for ENISA
no L7 termination for sensitive data

Multi-zone protection for the ENISA CRA portal and the data-submission site. Several control layers on anycast POPs and dedicated boxes, OK / KO / unknown decisioning, and for sensitive data a passthrough straight from AL4 to origin — without termination. The same product is cloned for banks.

Customer
ENISA (pilot)
Classification
TLP:AMBER · internal + ENISA
Status
Draft — no production changes
Owner
Josef Grill (CEO)

01Goal and principle

What we build and why. ENISA needs to protect its CRA portal and its data-submission site. We deliver a top-tier solution built on security-by-design.

▸ Principle

The TLS termination boundary = the data-processing boundary. In the sensitive part WGP does not terminate → does not process content → it decides only by the profile (L3/L4) learned where we do terminate (login). It lets the good through, blocks the bad, and sends the unknown to login. Authorization is held by the application; WGP is an attack filter.

02Traffic planes and three zones

We split traffic so that as little as possible — and as controlled as possible — reaches the sensitive part.

PlaneContentTLSHow we protect
CDN (static)Images, CSS, scripts — separate domain, separate certificate, no sensitive dataterminated at CDNFully under our control; the separate domain prevents HTTP/2 coalescing with the sensitive host
Zone 1 — portalLanding page (static)terminatedFully cached + microcaching → static is practically unattackable
Zone 2 — loginLoginterminated (box)Background bot detection + tiered challenge; the profile is learned at login
Zone 3 — sensitiveAccounts, data submissionpassthroughNo cert. Only verified (OK) passes from AL4 straight to origin; KO blocked; otherwise not allowed

03Control layers — anycast POP and dedicated box

Every point has several layers (different HAProxy instances and other tools). On the box, one sticky table shares state across the whole box; Redis distributes it to other boxes and up to the edge.

ANYCAST POP (×N worldwide) XDP volumetric + JA4T (from SYN) AL4 L4 filter · OK/KO lookup · block KO here CDN + AVC static + portal · microcache → forward to box only non-cacheable / sensitive Redis (edge): block KO at anycast DEDICATED BOX (at origin) AL4 passthrough · zone 3 → origin / block ACT / ACU termination · JA4 / H2 / QUIC fp ALB bot-check · challenge · write OK/KO AVC · AL7 · ADB cache · L7 · dispatch to origin ATP challenge PoW / captcha SHARED STICKY — across the whole box Redis · distribute to other boxes + edge
Fig. 1 — Layers on the POP and on the dedicated box. Sticky shared across the box; Redis distributes OK/KO to other boxes and to the edge.

04What happens to a request

Depending on the content type and the visitor state (unknown / OK / KO) the request goes elsewhere. Switch the scenario and follow the path and what happens.

Client request Edge · AL4 / CDN OK/KO lookup CDN cache static + portal Login · zone 2 bot-check + challenge Origin · sensitive zone passthrough from AL4 Block AL4 (box & anycast)
Where
—
What happens
—
Termination / profile
—
Fig. 2 — Static and portal come from CDN cache; a new visitor to sensitive without OK is redirected to login; OK goes passthrough to origin; KO falls at AL4.

05Login and bot detection

We send the request to the login portal together with a bot check — in the background, invisibly. The selection is selective by IP type.

Visitor typeApproach
Home / residential IPInvisible bot detection first; a challenge only on suspicion
Datacenter / VPN / TorStraight to a harder challenge (PoW / visible captcha)
Known bad IP / fingerprintKO at the edge — never even reaches login
▸ After login

Successful authorization → the client is marked OK (profile). A few failures → KO. Both are written locally, to the box-shared sticky and to Redis.

06Multi-layer limits and rules

On every layer (anycast and dedicated) we can limit or block connection and access counts (including at L7) and other metrics, and apply rules accordingly.

Dimension (and combinations)MetricAction
per IP · per ASN · per IP categoryconnection count, concurrency, request count (L7), ratePASS — allowed
PoW — challenge of varying difficulty
BLOCK — various methods
per country (GeoCC) · per continent
combined with JA4 / JA4T / other parameters
▸ Block page in CDN cache

A block can return an info page (what happened, who to contact, a request summary) served from CDN cache — attacking this page does not matter, it is fully cached and contains no sensitive data. Example in section 07.

07Block page (from CDN cache)

Example of the page a blocked visitor sees. Themed like our "origin down" pages: explanation, contact, a copyable request summary. Available in all official EU languages. WEDOS and ENISA logos.

https://portal.enisa.europa.eu/  ·  HTTP 429
WEDOS ProtectionENISA

Access temporarily restricted

Request blocked by WEDOS Global Protection

This request was temporarily blocked by attack protection. If you are an authorized user, please try again shortly, or sign in. If the problem persists, contact support and include the request summary below.

Request summary (copy for support)
Ref:    a1b2c3d4-ee55-46f7-9a01-d3f2c7b18e90
Time:   2026-06-28 09:41:07 UTC
Reason: rate-limit / reputation
Node:   edge-anycast (LU)

Contact: soc@enisa.europa.eu  ·  wedos.com

BGESCSDADEETELENFRGAHRITLVLTHUMTNLPLPTROSKSLFISV

Available in all 24 official EU languages. The page is fully cached in the CDN — attacking it requires no origin resources.

Fig. 5 — Example block page served from CDN cache (WEDOS + ENISA logos, explanation, contact, copyable request summary, language selection).

08Profile and signals

The profile has two levels. The rich profile decides on the box (where we terminate). The thin key propagates downward — only from it can AL4/edge evaluate OK/KO.

SignalLevelAt AL4?Note
IPthin keyanounstable (mobile) — strict: change = block + re-login
JA4thin keyfrom learningnative after termination (ACT/ACU)
JA4Tthin keyfrom XDPfrom SYN; XDP at edge → TLV (phase 2)
ASN / GeoCC / IP classthin keyanostable complement; drives challenge selection
JA4H · HTTP/2 · QUIC fprichneonly after termination; refines the OK decision
▸ Fingerprint stability — enforce HTTP/2 only

For the protected portal (zones 2/3) enforce HTTP/2 only (TCP) — disable HTTP/1.1 and HTTP/3. One ALPN, one transport, no fingerprint change during the session. Also JA4T requires TCP — it does not exist over HTTP/3 (QUIC). The machine-to-machine endpoint (data submission) is handled separately (mTLS); CDN/static may keep h3.

▸ To be candid

Combining signals increases uniqueness, not unforgeability — a targeted attacker clones the fingerprint. So it is a filter, not a gate; the real boundary remains auth at the origin.

09Propagation, latency and failure

State is written only by the terminating layer (ALB, after the auth result). AL4 and edge only read. The hot path always reads locally; the times below are for replication only — Redis is never in the synchronous path.

Propagation layerLatencyNote
Local sticky (same HAProxy)instantprocess memory
Box-shared sticky (local peers)sub-ms – a few msbetween processes on one box
Redis → other boxes (in region)a few – tens of msreplication, not hot path
Redis → edge POPs / cross-continenttens – ~100+ msWAN RTT; KO propagates globally
▸ When a dedicated box fails

We balance traffic across all locations, so a failure = only reduced capacity. The edge removes the failed location from balancing; a new box reads the profile from Redis → the client continues without re-login (if within the window). If the record has expired (300 s) or was not yet replicated → re-login. KO propagates the same way → the attacker stays blocked.

10Topology and failover — we recommend 3+ locations

We balance traffic across all dedicated locations (active/active). A failure of one = reduced capacity, not a service outage. With 3+ we can service one while another may simultaneously fail, and still keep running.

FAILOVER (HA)
Anycast POP Anycast POP Anycast POP EDGE · anycast XDP + AL4 health-check Redis: blocks Dedicated box · Hluboká (CZ) dedicated POP for ENISA ACTIVE Dedicated box · Luxembourg (LU) dedicated POP for ENISA ACTIVE Dedicated box · TBD location third location 3+ ACTIVE Origin sensitive data Redis · profile shared across locations All active — full balancing
Fig. 3 — Active/active balancing across all locations. A failure of one = reduced capacity, the service keeps running. Redis shares the profile → no re-login.
Number of locationsAssessment
1SPOF — failure = service outage. Distant users high RTT. Maintenance = outage. Not for production.
2HA yes, but on failure the other carries 100% load (2× headroom required). Even number → no quorum. Limited coverage.
3+ recommendedSurvives one failure with distributed headroom (n−1). Better coverage and RTT. Odd number enables quorum. Rolling maintenance without outage.

11Termination vs passthrough

The point where the lock opens is the TLS termination point = where WGP sees into the content. For the sensitive zone it opens only at the origin.

Client browser Edge XDP + AL4 Box 3 zones Origin sensitive data termination here
TLS termination
—
WGP sees
—
CRA / data
—
Fig. 4 — In zone 3 the lock opens only at the origin. A KO request (repeatedly not logged in) falls at AL4 immediately.
▸ Two KO block points

We block KO first on the dedicated box. Once KO propagates via Redis to the edge, we block it already at the anycast POP — an extra situation: cheapest and global, the attacker never reaches the box.

12Alternative: termination + E2EE payload (HPKE)

Proposed as an alternative / option to passthrough zone 3 (not a replacement). When ENISA wants full L7 protection on the sensitive flow together with a guarantee that we cannot read the content: we terminate TLS, but the request/response bodies are end-to-end encrypted with a key we never hold. In exchange for integrating client-side crypto into ENISA's application.

Two layers: outer TLS (ours) + E2EE payload (ENISA only) Client browser JS / M2M HPKE encrypt WGP · L7 termination sees: JA4, headers, sizes → rate-limit, bot, WAF, challenge does not see: content (ciphertext) Origin HPKE decrypt private key in HSM outer TLS — we terminate E2EE payload (HPKE) — only ENISA opens it the envelope passes WGP as ciphertext
Fig. 6 — We terminate the outer TLS at WGP (full L7 protection over structure and metadata). The payload is in an HPKE envelope opened only at the origin — we see only ciphertext.

The client (JavaScript in the browser or a machine-to-machine client) wraps only the body in an HPKE envelope (RFC 9180) to the ENISA server's public key. Only the payload is encrypted, not the whole HTTP — structure, headers, sizes and JA4 stay readable to us for L7 protection. We terminate the outer TLS, see only ciphertext, and over the envelope we apply rate-limiting, bot detection, challenges and structural WAF (valid envelope format, max size) before the origin. The origin decrypts the envelope; its private key is in an HSM. Note: do not use nested TLS (TLS-in-TLS) — that would turn the body into opaque bytes and we would lose L7 protection. Only the payload is encrypted.

HPKE for humans and machines — one envelope, separate key acquisition

Yes, HPKE can be used for humans too. The data plane is one envelope for everyone; only how the client obtains the key and proves it is authorized differs. Confidentiality to the server is available to everyone — HPKE Base mode to the server's public key works even without a client key. Sender authentication (“authorized only”) is provided by Auth mode for anyone holding a client key; for password users it is replaced by an OPAQUE session.

ParticipantEnrollmentKey storageProof of authorizationRotation / revocationMove to another device
Machine-to-machine (M2M)keypair issued at provisioningsecret manager / HSM — key never leaves the clientregistered public key on the server (Auth mode)new key + remove old from registryn/a (client is a machine)
Human · trusted devicebrowser generates a keypair at first loginIndexedDB — non-extractable key (WebCrypto)registered public key (Auth mode)re-enroll the device keyvia OPAQUE fallback or key escrow
Human · password onlyno key in advanceno storage — key is unlocked from the passwordOPAQUE (PAKE) session + optionally a wrapped keypassword change = re-wrap the keyworks on any device (password is enough)
▸ How to combine

Bidirectional: from one HPKE setup we export a session key and both request and response run over AES-GCM with one key. Recovery must be E2EE-safe (recovery code / escrow share), not silent server reading. The server holds: its own HPKE keypair (HSM), a registry of authorized client public keys (Auth mode + revocation) and OPAQUE verifiers for password users. Browser-native path: ECDH(P-256) + HKDF + AES-256-GCM (all in WebCrypto), or an HPKE library (often WASM). OPAQUE/Argon2 require a library.

Weakness: integrity of crypto-code delivery

In the browser, E2EE is only as strong as the integrity of the code that encrypts. Anyone who serves the page or can modify it could substitute crypto that sends the key or plaintext out. Because we terminate the outer TLS, we are structurally in a position to do this — so the guarantee against us is only as strong as the protection of code delivery. This is the well-known criticism of in-browser crypto (and of services like Mega). We address it in layers:

MeasureWhat it addresses
Root of trust outside WGPServe the bootstrap HTML and the crypto bundle via passthrough (zone 3) or from an ENISA origin with its own cert. Whatever carries trust must not pass through a layer we can modify.
SRI (Subresource Integrity)The bootstrap HTML pins the bundle hash; the browser rejects a tampered bundle. (But the hash itself must come from a trusted source — see above.)
Code signing / PWA / extensionStronger binding to specific code than SRI alone.
TransparencyPublished hashes, reproducible build, independent audit.
Native / M2M clientNo JS delivery → strongest. ENISA controls the binary.
▸ Residual risk (to be candid)

Even with SRI, the bootstrap document carrying that hash must arrive with integrity — if we serve it, we could change the hash. So the root of trust must sit outside WGP (ENISA origin or passthrough). The strongest guarantee comes from a native/installed client. And metadata (sizes, timing, paths) we see regardless → traffic analysis; mitigate with padding and uniform endpoints.

When passthrough and when E2EE

PropertyPassthrough (zone 3)Termination + E2EE payload
Integration in ENISA's appnonerequired (client-side crypto)
L7 protectionL3/L4 + profile onlyfull L7 (over the envelope)
Do we see content?no (we don't terminate)no (E2EE) — even though we terminate
Do we see metadata?L3/L4HTTP structure + sizes + JA4
Suitable forwhen ENISA cannot change the appthe data-submission site; when it can integrate
▸ Note

The origin always authorizes — holding the key is the proof of authorization. This option is also a candidate for resolving open point 5 (machine-to-machine endpoint) at the application layer. For CRA: we terminate (full L7) yet provably cannot read the content — stronger data minimization.

13Solution components

Components already in place and components that will be part of the solution.

ComponentBenefitStatus
Multi-layer limits (IP/ASN/cat/CC/continent + combos)Rules on every layerhave
Tiered PoW / captchaDumb and smart attackshave
Sanitizing client trust headersOK cannot be spoofedhave
Separate domain/cert for CDNNo coalescing of the sensitive hosthave
KO up to the edge (global)Attacker caught most cheaplypart of solution
Rate-cap on OK tooA hijacked OK cannot flood the originpart of solution
State written only by ALB (AL4 read-only)Single source of truthpart of solution
Block page from CDN cache (multilingual)Attacking it does not matterpart of solution
Demote OK → unknown on anomalyASN/geo jump → re-authpart of solution
mTLS / API key for machine-to-machineHard anchor for data submissionto be decided

14CRA alignment (EU 2024/2847)

The model is a direct security-by-design argument: in the sensitive zone WGP does not terminate → does not process content = data minimization and attack-surface reduction (Annex I).

DateWhat applies
11 Sep 2026Reporting (Art. 14): report actively exploited vulnerabilities and severe incidents to ENISA/CSIRT within 24 h. The nearest action point.
11 Dec 2027Full application: essential requirements, conformity assessment, CE marking, documentation.
▸ Note

Product vs. service is a matter of interpretation for the legal/ENISA channel. 300 s data retention = demonstrable minimization; zone 3 content is not logged (passthrough).

15Our rules (specification)

Binding rules by which we build the solution. One point remains open for agreement (below).

#RuleSpecification
1XDP at the edgeWe deploy XDP on anycast POPs — volumetric protection and JA4T extraction from the SYN. The kernel code passes internal review (Jakub). Binding.
2Transport POP → boxBetween the anycast points and the dedicated box: public transit with an allowlist (WGP IPs only). From the dedicated box we offer both public transit and a private backbone — per agreement.
3Protocol of the protected portalWe enforce HTTP/2 only (TCP); HTTP/1.1 and HTTP/3 disabled. Stable fingerprint and JA4T requires TCP. The machine-to-machine endpoint is handled separately (point 5 below).
4Profile — phasingPhase 1: IP + JA4. Phase 2: + JA4T. Target state = all signals.
5Mobile in zone 3Strict — IP change = block + re-login. No exceptions.
▸ Open for agreement

Machine-to-machine endpoint (data-submission site): mTLS / API key at the origin as a hard anchor — still open. Until agreed, this endpoint runs in the same mode as a human (profile IP + JA4 (+JA4T)).

16What we can protect (capability overview)

ENISA asked about captcha — yes, and it is just one tool among many. Below is an overview of the layers, signals and actions we can decide on. Everything is configurable per domain (Anygma profile) and freely combinable; not everything is enabled by default — the exact set is tuned per deployment.

▸ On captcha specifically

Captcha is one challenge option. We handle most traffic invisibly (background bot detection) or via risk-tiered PoW; a visible captcha we deploy selectively (datacenter / VPN / Tor / suspicion), not blanket — for UX reasons. A challenge is just one of many possible outputs of a rule.

Layers — where we decide

LayerWhat we can do there
L3/L4 · XDP, AL4Volumetric protection, SYN handling, JA4T from SYN, connection limits, anycast absorption
TLS · ACT / ACUJA4, HTTP/2 fingerprint, QUIC fingerprint (after termination)
L7 · ALB / AL7JA4H, headers, path, method, WAF, challenges, OK/KO/unknown decisioning
Cache · AVCMicrocache, static, origin offload, block page from CDN
Challenge · ATPInvisible detection, PoW (tiered), captcha

Signals and parameters (hundreds of combinations)

CategoryParameters we decide on
Network / identityIP, prefix, ASN, country (GeoCC), continent, IP category (datacenter / residential / VPN / Tor / search-engine), GeoASN
FingerprintJA4, JA4T (TCP/SYN), JA4H (HTTP), HTTP/2 fingerprint, QUIC, JA4 composite
Reputation (feeds)Spamhaus DROP / ASN-DROP, abuse.ch Feodo / ThreatFox, GreyNoise RIOT / Business allowlist
HTTP attributesUser-Agent (blacklist / bad / old / AI / missing / short / whitespace), Referrer, Content-Type, method, path, headers, cookies (login)
Behaviorrate (req/min), concurrency, connection count, 404/301 patterns (Behavior Shield), honeypot, behavioral baseline
ApplicationCMS autodetection (WordPress / Drupal / Magento / PrestaShop / Joomla) → tailored rules; WebSocket; combo engine (combining dimensions)

Limits — per dimension and in combination

We can limit and block per IP / ASN / country / continent / category / path and their combinations with JA4 / JA4T and other parameters. Metrics: connection count, concurrency, request count (L7), rate. That yields on the order of hundreds of possible rules per domain.

Actions — what we do with it

ActionVariants
PASSpasses unchanged
LOGlog only (monitoring, no action)
RATE-LIMITper any dimension above
CHALLENGEinvisible detection / PoW (tiered) / captcha
BLOCKdrop, 4xx, block page from CDN cache
▸ Note

Everything is configured per domain via the Anygma profile and is combinable (combo engine). We log traffic to OpenSearch (18-month retention, correlation across layers via the trace UUID). The exact enabled rule set is a matter of deployment and agreement with ENISA.

17Version history

VersionDateChange
1.2.02026-06-28Expanded the E2EE/HPKE alternative (humans and machines in detail, code-delivery weakness); added the capability overview (layers, signals, limits, actions).
1.1.02026-06-28Added alternative: termination + E2EE payload (HPKE) — one envelope for humans and M2M, OPAQUE for password users, comparison with passthrough.
1.0.02026-06-28First released version for ENISA.
▸ Status

Draft for approval. No production change. Once approved → technical specification, then configuration (versioned from 1.0.0, staged rollout, Marek and Ivan notified).