惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
D
Docker
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Project Zero
Project Zero
Engineering at Meta
Engineering at Meta
J
Java Code Geeks
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Simon Willison's Weblog
Simon Willison's Weblog
S
Security Affairs
NISL@THU
NISL@THU
T
Tor Project blog
A
About on SuperTechFans
宝玉的分享
宝玉的分享
腾讯CDC
S
Schneier on Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
P
Privacy & Cybersecurity Law Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
雷峰网
雷峰网
C
Cyber Attacks, Cyber Crime and Cyber Security
Vercel News
Vercel News
Cisco Talos Blog
Cisco Talos Blog
D
DataBreaches.Net
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
L
LINUX DO - 热门话题
Microsoft Security Blog
Microsoft Security Blog
Latest news
Latest news
C
Check Point Blog
有赞技术团队
有赞技术团队
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
云风的 BLOG
云风的 BLOG
SecWiki News
SecWiki News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
爱范儿
爱范儿
月光博客
月光博客
V
Vulnerabilities – Threatpost
T
Threat Research - Cisco Blogs
P
Palo Alto Networks Blog
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Webroot Blog
Webroot Blog
S
Security @ Cisco Blogs

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
RSC Is Not the Input Boundary
Viktor Lázár · 2026-05-10 · via DEV Community

Every major React Server Components security release seems to trigger the same little ritual. An advisory lands, someone sees the letters RSC, and a few hours later the lesson has already collapsed into: "RSC is bad."

That lesson is convenient. It is also imprecise.

The same thing happened around the Next.js security release from May 7, 2026. Vercel shipped fixes for several Next.js and upstream React issues, including a high-severity denial-of-service vulnerability affecting the React Server Components packages. But the interesting part of the advisory was not that rendering a Server Component is inherently dangerous. The interesting part was that specially crafted HTTP requests sent to Server Function endpoints could cause excessive CPU usage or out-of-memory failures while the payload was being processed.

That distinction is not a footnote. It is the center of the issue.

A Server Component is not the same attack surface as a Server Function. One sends a representation of a component tree from the server to the client. The other receives a payload from the client, asks the server runtime to deserialize it, and then invokes server-side code. They can both live inside the RSC model. They can both involve the Flight protocol. But from a security perspective, they ask opposite questions.

The Server Component question is: what are we allowing to leave the server and reach the client?

The Server Function question is: what are we allowing to enter the server from the client?

The second one is an input boundary. If that boundary is enforced too late, the failure is not that the RSC model is broken. The failure is that an RPC-shaped input surface was treated as if it were merely a framework ergonomic.

The Category Error

There is a recurring confusion in RSC discussions. People often talk about "RSC" as one thing, when in practice they are combining several distinct mechanisms:

  • Server Components: components that run on the server.
  • Client Components: components that run in the browser, while still participating in the same React tree.
  • Server References / Server Functions: server-side functions for which the client receives a reference and can later issue a call.
  • Flight protocol: the serialization format that carries component payloads, references, and a broader set of values between the server and the client.

Together, these form an architecture. They do not share the same risk profile.

When a Server Component renders, the direction of execution is primarily server to client. The server produces a payload. The client consumes it. The usual class of bug is that the server puts something into that payload that it should not have put there. That can be a data leak, a cache-boundary mistake, or a component-level authorization bug.

When a Server Function runs, the direction reverses. The client sends something to the server. The server runtime has to understand the payload, identify the action, materialize the arguments, and pass them to the handler.

That is a very different moment. The browser is no longer just a consumer. The browser, or anything capable of sending an HTTP request, is now providing input to the server.

An endpoint like that cannot be treated as a React composition detail. It is a public RPC surface. It may look like a function call to the developer. TypeScript may make it feel wonderfully local. Over the network, it is still a hostile input boundary.

What Happens in a Server Function Call?

In simplified form, a Server Function request looks like this:

client event
  -> POST request
    -> identify action id / server reference
      -> deserialize Flight payload
        -> materialize arguments
          -> invoke server function handler

Enter fullscreen mode Exit fullscreen mode

Most application code focuses on the last step:

async function updateProfile(input) {
  "use server";

  const data = schema.parse(input);
  await db.user.update(data);
}

Enter fullscreen mode Exit fullscreen mode

At the application level, this is better than nothing. The handler is not blindly trusting the input. But for the class of problem described in the 2026 advisory, this is already late.

By the time schema.parse(input) runs, the runtime has already done much of the risky work: it has read the request, walked the payload, materialized values, built objects, interpreted references, and potentially dealt with streams, binary values, and nested structures. If the goal of the attack is not to smuggle invalid business data into the handler, but to make deserialization itself consume too much CPU or memory, validation inside the handler does not protect the server from the relevant cost.

So "validate your input" is not specific enough.

The question is where.

If validation happens inside the handler, it protects application invariants.

If validation happens in the Server Function layer after the request has already been deserialized, it gives the developer a better contract, but it may still leave the decoder cost exposed.

If validation happens while the protocol payload is being deserialized, the runtime can know during the argument walk what it expects, what it should drop, what it should reject, and when it should stop processing the request.

That is the difference that matters.

A WAF Is the Wrong Boundary

One important line in Vercel's release was that these advisories could not be reliably blocked at the WAF layer.

That should not be surprising.

A WAF sees HTTP requests. It can inspect headers, size, URLs, known patterns, maybe parts of the body. It does not fully understand the semantics of a Flight payload. It does not know which function a given server reference points to. It does not know how many arguments that function expects. It does not know that slot zero must be a string, slot one must be FormData, slot two must be a Map<string, number>, and the file field must be at most five megabytes and either image/png or image/jpeg.

If the WAF tried to know all of that, it would effectively be reimplementing the framework protocol at the edge. That is brittle, version-dependent, and it puts the responsibility in the wrong place.

The right boundary is where the runtime already knows which Server Function it is about to call, but has not yet handed materialized input to the handler.

That is the protocol layer.

This Is Not a TypeScript Problem

Types usually enter the discussion here. A Server Function might look like this:

async function savePost(post: PostInput) {
  "use server";
  // ...
}

Enter fullscreen mode Exit fullscreen mode

The developer experience suggests that post is a PostInput.

From the network's point of view, that is only a hope.

The TypeScript type does not exist in the request. It does not exist in the Flight payload. It will not tell the decoder when to stop. It will not reject an overly deep structure, an oversized string, an oversized binary value, an unexpected FormData field, or a Map whose size is itself enough to become a denial-of-service attempt.

Types are useful documentation for the contract. But if the contract protects a runtime boundary, runtime information has to exist too.

That is why the Server Function definition needs metadata that does more than narrow the handler's TypeScript type. The metadata has to reach the protocol decoder.

What Late Validation Looks Like

Consider an abstract Server Function API:

const savePost = createServerFn()
  .inputValidator(postSchema)
  .handler(async ({ data }) => {
    await db.post.create(data);
  });

Enter fullscreen mode Exit fullscreen mode

This is a good direction. Validation lives at the definition site, not scattered through the handler body. The handler receives validated data. TypeScript inference moves together with the runtime schema. An API like this is much healthier than a bare async function (input: Whatever) and a comment saying "the client calls this."

TanStack Start is on this side of the line. Its createServerFn API makes the Server Function explicit, treats the input validator as part of the function contract, and documents that client-side calls become network calls. That is much better than hiding the request-shaped nature of the operation.

But it is still a different category.

A TanStack Start Server Function is not an RSC Flight Server Function in the same sense as an RSC server reference. Based on the documented API, validation is part of the Server Function layer: the function receives a data input, the runtime validates that input, and then the handler runs. That is a good application-level contract. If the runtime has already deserialized the body into a JavaScript value before the validator sees it, then the validator is working in the post-deserialization world.

This is not a criticism in the sense of "TanStack Start is bad." It is not. A definition-site validator is the right direction for a classic RPC API.

It is simply not the same protection as giving the Flight decoder the Server Function's argument-slot contract and letting validation happen during the payload walk.

For an RPC API, the question is how much work the framework's serialization layer has to do before the validator gets control. For an RSC Server Function, the question is even sharper because the Flight payload can carry a richer value space. We are not only talking about JSON objects. The protocol can represent references, form data, binary values, streams, iterables, promises, typed arrays, Map, and Set.

The richer the wire format, the less satisfying "we parse it at the top of the handler" becomes.

The react-server Approach

The @lazarv/react-server approach is not merely to provide a convenient validation wrapper around the handler.

The important part is that the Server Function definition attaches metadata to the server reference, and that metadata reaches the Flight decoder.

For example:

import {
  createFunction,
  formData,
  file,
} from "@lazarv/react-server/function";
import { z } from "zod";

export const uploadAvatar = createFunction([
  formData(
    {
      displayName: z.string().min(1).max(80),
      avatar: file({
        maxBytes: 5_000_000,
        mime: ["image/png", "image/jpeg"],
      }),
    },
    { unknown: "reject" }
  ),
])(async function uploadAvatar(form) {
  "use server";

  const displayName = form.get("displayName");
  const avatar = form.get("avatar");

  await saveAvatar({ displayName, avatar });
});

Enter fullscreen mode Exit fullscreen mode

The point is not only that form.get("avatar") becomes nicer inside the handler.

The more important contract is this:

  • the first argument to the Server Function is FormData;
  • the allowed fields are known;
  • unknown fields can be rejected by default;
  • the file has a size limit;
  • the MIME allowlist is part of the wire contract;
  • the handler only runs if the decoder successfully validates that slot.

That is not business logic. That is an input boundary.

Slot-Walk Validation

The technical shape is roughly this.

When a Server Function export is wrapped with createFunction(...), the parse/validate spec associated with that wrapper is registered as server reference metadata. When a request comes in, the runtime first tries to recover the action id. For header-based action calls, that can come from the react-server-action header. For progressive-enhancement form submissions, it can be encoded in the submitted FormData. If the token is encrypted, the runtime decrypts it first so it knows which action the request is trying to call.

Then comes a small but important step: the action module has to be loaded before decoding.

That may sound incidental. It is not. The server-function metadata registry is populated by the module's top-level registerServerReference(...) calls. If the runtime deserialized the payload first and only loaded the action module later, the first call to an action could silently skip validation. So react-server preloads the action module first, then calls decodeReply with the recovered action id.

From there, the decoder is no longer walking the argument list blindly. It knows which Server Function it is decoding for. It can look up the associated metadata. It can apply parse and validate slot by slot.

If the first argument is z.string(), slot zero has to validate as a string.

If the second argument is arrayBuffer({ maxBytes: 1024 }), the decoder can reject an oversized buffer based on byte length.

If a formData(...) spec uses unknown: "reject", an injected extra field does not reach the handler.

If a file(...) spec declares a MIME allowlist and a size limit, the runtime does not wait for application code to decide whether the file is acceptable.

If a map(...) or set(...) spec has a maximum size, the collection cannot grow without bound in the pre-handler world.

If a stream or async iterable has a maximum chunk count or byte limit, the boundary remains active as the handler consumes it.

That is the key property: the shape of the Server Function input is not only TypeScript inference. It is a decoder contract.

Failure Is Structural

A protocol-level validation failure is not a business validation failure.

It is not the same as a user typing a bad email address into a form and receiving a field error. It means the wire payload did not satisfy the contract under which the server was willing to materialize a Server Function call at all.

The right response is structural rejection.

In react-server, a validation failure during the slot walk becomes a DecodeValidationError and is mapped to a 400 response. The handler does not run. The argument list is not bound. The client does not receive detailed schema diagnostics, because those details can reveal useful shape information to an attacker. The operator log can still keep the useful parts: action id, slot index, and failure reason.

Again, this is different from application-level validation.

A form validation error is a user experience concern.

A decode validation error is a protocol concern.

If we merge those two paths, we either reveal too much to an attacker or give too little feedback to a real user. They should not be the same path.

Bound Arguments Are Not Call Arguments

There is another detail that is easy to lose in RSC Server Function discussions: call arguments and bound captures are not the same thing.

A Server Function can be created with bound values. These are values carried by a server-side closure or binding and later associated with the server reference. They should not be treated the same way as runtime arguments sent by the client.

In the react-server model, bound captures are integrity-protected by the action token. That is a different kind of protection than per-argument validation. They do not need the same schema path as client input, because they are not crossing the same trust boundary.

Arguments sent by the client are hostile input.

Bound captures are integrity-protected server-side state representation.

If both are collapsed into the same "validate the input" bucket, the model becomes muddy again.

Global Decode Limits

Per-function contracts need a second layer: global resource ceilings.

There will be unvalidated legacy actions. There will be code in the middle of migration. There will be Server Functions where some slots are intentionally loose. And there are payload characteristics that should not have to be repeated manually on every function.

So the runtime needs limits such as:

  • maximum payload byte size;
  • maximum Flight row count;
  • maximum materialization depth;
  • maximum number of bound arguments;
  • maximum BigInt digit count;
  • maximum string length;
  • maximum stream chunk count.

These do not replace per-function validation. They are the safety floor. The function spec is the precise contract. The global limits are the ceilings that still stop obviously abusive payloads when a function has not yet been declared perfectly.

Together, they form a more meaningful defense.

Dev-Time Strictness

A runtime's behavior is not only what it does in production. It is also what it teaches during development.

If a "use server" export can be called from the client without validation, that is an attack surface that may not be visible at the call site. The developer sees a function. The browser sees an endpoint. The reviewer often reads the handler body, not the wire boundary.

That is why a dev-time warning for bare Server Functions is useful:

Server function ... called without validation

Enter fullscreen mode Exit fullscreen mode

The point is not that every function needs a complex schema. Some functions have no input. Some migration paths need a temporary escape hatch. But that should be an explicit decision. The default should not be that a publicly callable Server Function has no runtime input contract and nobody notices until a security release makes the boundary visible.

In that sense, the no-spec createFunction() form is useful too. It does not add validation, but it records intent. The runtime can tell that the developer has seen the boundary and chosen not to narrow it yet.

The Missing Runtime Contract in Next.js

Next.js fixed the affected upstream React issues, and everyone affected should upgrade. That is not optional. After an advisory like this, the first correct move is always to patch.

But patching is not the same thing as learning the architectural lesson.

In the current Next.js Server Function model, there is no generally documented framework API that gives the runtime a per-function Flight decode contract. There is "use server". There is a server-side handler. You can validate inside that handler. You can build your own helper around it. But that is not the same as attaching argument-slot metadata to the server reference so the decoder knows what it is allowed to materialize before the handler runs.

That is why I consider the react-server approach stronger here.

Not because it has "schema validation." Schema validation exists in many places.

Because the validation happens in a better place.

Because the function contract appears on the Flight protocol decode path.

Because malformed payloads can be structurally rejected before handler execution.

Because the wire-aware specs cover not only application data models, but also the richer value space of the protocol: FormData, File, Blob, ArrayBuffer, typed arrays, Map, Set, streams, iterables, and promises.

And because this defense is not a WAF rule, not a convention, not "remember to parse at the top of the handler," but a runtime boundary.

A Server Function Is a Public Endpoint

The simplest way to say all of this is:

A Server Function is a public endpoint.

Not because it looks like a REST route. Not because the developer wrote a URL for it. Because the client can send a request that causes the server to attempt to invoke a function.

Once we accept that, the security consequences become clearer:

  • every Server Function should have an input contract;
  • the contract should live at the definition site, not be scattered through the handler body;
  • the runtime should know the contract as early as possible;
  • deserialization cost should be bounded;
  • unknown fields should not be treated as harmless by default;
  • file and blob inputs should have size and MIME constraints;
  • authorization should be explicit in the Server Function, not inferred from the surrounding component tree;
  • the WAF should be an extra layer, not the primary interpreter.

This is not an anti-RSC position.

It is the position that takes RSC seriously enough not to treat all of its parts as one mystical box.

RSC Is Not the Scapegoat

The interesting thing about RSC is that it gives us a formal boundary between two different execution environments. The server and the client are not the same place. They have different capabilities, different costs, different failure modes, and different security responsibilities.

That is the strength of the model.

But a boundary is only useful if we are precise about what crosses it, and in which direction.

For Server Components, the question is what the server sends to the client.

For Server Functions, the question is what the server accepts from the client.

When a Server Function input payload is validated too late, or when the runtime does too much work before it even knows what it expects, the lesson is not that Server Components are a bad idea. The lesson is that an RPC-shaped input surface was treated as framework ergonomics for too long.

That mistake is fixable. But only if we name it precisely.

Not "RSC is bad."

Not "Server Components are insecure."

This:

Server Function input payloads need protocol-level validation.

That sentence is less dramatic. It is also more true.

And if we want RSC to have a healthy future, that is exactly the kind of sentence we need: less drama around the model, and more attention on the few boundaries where the model actually meets a hostile network.

References