This illustration puts a whole data path on one page: one SVG file, the client that displays it, every server it passes through, and the runtimes and containers underneath. It is built to answer one question at each step: who can read the data here?
The reasoning behind each box, and the fix for every gap, is in the companion article, Machine Code/Rust/WASM, SVG/Native, Server/Client.
1. How to read it
| Mark | Meaning |
|---|---|
| Solid box | A step where data passes through and a control holds |
| Dashed box | A gap: data is stored, cached or exposed there, or code can run |
| Dashed circle with a number | Points to one of the 31 gaps listed at the bottom of the diagram |
| Dashed arrow | Traffic that is plaintext by default (between Kubernetes pods) |
| Grey arrow labeled TLS | One TLS session. The data is decrypted in the box at each end |
| "decrypts here" | Inside this box the data is plaintext, whatever the arrows say |
The diagram reads top to bottom in seven bands, each building on the one above.
2. The seven bands
1. One SVG, three ways in. The source file holds a hidden <script> and patient details in <metadata>. Base64 turns it into a data: URI without changing any of it. How a page displays it decides whether the script runs: never through <img>, always when inlined or loaded in <object> or <iframe>.
2. Four words that get confused. Base64 (an encoding), compile (a translation into a new program), machine code (what the CPU runs) and bare metal (code with no operating system underneath). Only compiling changes what code can do. Bare metal is dashed because a memory bug there takes over the whole device.
3. The request path. Six boxes from the Elm client to a Rust service, each split into what it checks and what it doesn't. This is where the Elm and Rust guarantees sit, and where their limits show.
4. TLS protects each hop, not the data. Two pipelines, labeled A and B: a Next.js server render followed by client-side hydration, and a CRM-to-Shopify data bus. Every box decrypts.
5. Same data, three stacks. Lanes C, D and E carry the same products, customers and consent through a JVM stack (Salesforce, MuleSoft, Salesforce Commerce Cloud), an iPaaS stack (SAP, Azure, Celigo, Magento) and a Wasm stack (Shopify Functions, Cloudflare Workers). A table compares them on seven concerns, including Consent Mode v2 and idempotency.
6. Isolation and transport. Where the wall sits in a virtual machine, a Docker container and a Kubernetes cluster, and how data crosses between them.
7. The gaps. All 31 gaps, each with its fix.
3. Where SVG, Rust and Elm appear
SVG is both the subject and the medium. Band 1 shows an SVG as a carrier of code and data (gaps 3 and 7), and the diagram itself is an SVG, which is why this page displays it with <img>. Gap 30 returns to it: card skimmers on Magento checkouts have been hidden in SVG onload attributes.
Elm is the first box of the request path (An Introduction to Elm). Its pure views, opaque types and ports keep a well-written client from leaking data by accident, but the box's "does not" side is gap 8: the browser is untrusted, so every rule has to be enforced again on the server.
Rust appears three times. Each idea links to the chapter of The Rust Book that explains it:
- The Rust service at the end of the request path: memory safety with no
unsafe, aConsentGrantthat is consumed on use (ownership), read-only versus exclusive access (references and borrowing), and aPii<T>type that redacts itself in logs and refuses to serialize. - Bare metal:
# and the site's own GLB parser, where memory safety is the only wall. - The Shopify Function in lane E: Rust compiled to Wasm, with no network access (gap 22 covers the host imports that remain).
Both languages share the same limit, shown on the Rust box: types can force a check to happen, but they can't prove the check is the right one.
4. Gap index
Where each numbered circle appears in the diagram. Fixes are in the companion article and at the bottom of the illustration.
| # | Gap | Where it appears |
|---|---|---|
| 1 | Base64 is not encryption | Band 1, base64 data URI |
| 2 | Encoding hides payloads from filters | Band 1, base64 data URI; Cloudflare edge |
| 3 | SVG executes when inlined | Band 1, source and display modes; Xano; Magento (lane D) |
| 4 | CORS is not access control | Cloudflare edge |
| 5 | The edge sees plaintext | TLS; Cloudflare edge; TLS Full (strict) |
| 6 | Logs keep what they're sent | Xano; Shopify / Xano API (lane A); CRM · Xano (lane B) |
| 7 | SVG carries data, not just pixels | Band 1, source metadata and <img> display |
| 8 | The client is untrusted | Browser · Elm |
| 9 | Compiled is not hidden | Machine code definition |
| 10 | Hydration ships data into the page | Browser hydrates (lane A) |
| 11 | Shared caches mix customers | CDN · edge (lane A) |
| 12 | Server fetch runs before consent | Browser request; Next server (lane A) |
| 13 | NEXT_PUBLIC_ compiles into the bundle |
Next server (lane A) |
| 14 | TLS is hop by hop on a data bus | Cloudflare Worker (lane B) |
| 15 | Unverified or replayed webhooks | Shopify webhook back (lane B) |
| 16 | Queue rows outlive the message | Queue · webhook table (lane B) |
| 17 | Admin tokens at the edge | Cloudflare Worker (lane B) |
| 18 | Middleware sees everything | MuleSoft; SFCC (lane C) |
| 19 | The JVM has no in-process sandbox | Salesforce core; SFCC (lane C) |
| 20 | Consent isn't carried with the event | Google Merchant (lanes C and E); Shopify Customer Privacy API (lane E) |
| 21 | Retries duplicate writes | Google Merchant (lanes C and E); Azure (lane D); Cloudflare Worker (lane E) |
| 22 | Wasm host imports are the door | Shopify Function (lane E) |
| 23 | Containers share the kernel | Docker panel |
| 24 | Kubernetes Secrets are base64 | Kubernetes panel, etcd |
| 25 | Pod traffic is plaintext by default | Kubernetes panel, arrow between nodes |
| 26 | Secrets baked into images | Docker panel |
| 27 | The host can read VM memory | Virtual machine panel |
| 28 | The iPaaS keeps copies | Celigo (lane D) |
| 29 | Integration credentials are too broad | SAP S/4HANA (lane D) |
| 30 | Checkout JavaScript gets skimmed | Magento (lane D) |
| 31 | Batch files sit in plaintext | SAP S/4HANA (lane D) |
5. The files
- SVG: svg-base64-security-gaps.svg, 1600 × 4290, with a
<title>and<desc>for screen readers and search. Text uses Helvetica and Courier, and the labels avoid arrow characters so they display in any app. - PDF: svg-rust-elm-illustration.pdf (233 KB), the whole diagram on one vector page, with selectable text, for printing or sharing.
- JPG: svg-base64-security-gaps.jpg, carrying the same rights XMP and alt text as every image on this site (see ALT, XMP and Favicons).
- Rights: see the rights page.
When you reuse the SVG on another site, display it with <img> rather than inlining it. That is gap 3 applied to this diagram.
6. Further reading
- The Rust Programming Language ("The Rust Book"):
- What is ownership?, the rule behind the single-use
ConsentGrant - References and borrowing, the
&versus&mutpermission split - Unsafe Rust, what "no
unsafe" rules out
- What is ownership?, the rule behind the single-use
- The Embedded Rust Book:
no_std, Rust on bare metal - Shopify: Rust for Functions, Rust compiled to Wasm
- An Introduction to Elm and Elm ports
- Machine Code/Rust/WASM, SVG/Native, Server/Client, the companion article with every fix