Why does EK9 require capability declarations for publishable packages?
← Package Capability Security · Ref: Q1272
Every major software supply chain attack of the last decade shares the same kill chain: a compromised dependency quietly accesses system resources — reading environment variables, opening network connections, writing files — that its stated purpose does not require, and exfiltrates data. A JSON parser and a credential-stealing trojan look identical in their published metadata on npm, PyPI, Maven Central, or crates.io. Nothing in those ecosystems tells a consumer what a dependency will do at the system level.
EK9 closes the gap structurally at the compiler. Every publishable package must declare the gated system types it uses in a 'capabilities' list. Once a package declares a 'capabilities' list, the compiler verifies the declarations match the actual code: you cannot use 'Stdout', 'TCP', 'File', or 'EnvVars' in a publishable module without declaring the matching capability. When a previously-pure package suddenly adds 'org.ek9.lang::TCP' to its capabilities list, that change is visible to every consumer the moment they fetch the new version from the repository — before a single line of it executes.
THE TWO CAPABILITIES EVERY ATTACK NEEDS
1. Reading secrets — EnvVars for API keys, File for credential files, Stdin for pipes 2. Exfiltration — TCP for network sockets, HTTPRequest for REST calls, File for disk
EK9 gates both. A package that declares 'capabilities <- ["org.ek9.lang::TCP"]' has explicitly said 'I need network access' — a claim that consumers can evaluate against the package's advertised purpose. A package whose capabilities list omits the network capability literally cannot open a socket in its non-dev code; the compiler refuses to emit the bytecode. Enforcement starts when the capabilities block is declared - a package with no block at all is not checked (see Q1276).
MOST PACKAGES NEED ZERO CAPABILITIES
A JSON parser. A collection library. A string-manipulation utility. A mathematical package. None of them touch system resources — they need no capabilities, so a reviewer should expect none to be declared; the compiler restricts a package only once it has a capabilities block (see Q1276). When a legitimate library author updates their package they can be confident no accidental capability has crept in; when an attacker tries to insert one, the change is unmissable.
THE COST
A few extra lines in your 'defines package' block when you write a publishable library. The occasional compile error when you start using a new gated type and forget to declare it. That's the entire developer tax.
THE BENEFIT
Structural supply chain defence. No silent access escalation. No JSON parser that quietly reads your AWS credentials. No 'helper utility' that opens a reverse shell. The capability change is a compile error before it's a compromise.
See Q1270 for what makes a package publishable. See Q1271 for the capability declaration syntax. See Q1273 for the full gated types list. See Q1277 for error E12010.
Example
defines module qa.packagecapabilities.whyrationale defines package version <- 1.0.0-0 description <- "Publishable package declaring the Stdout capability it uses" license <- "MIT" publicAccess <- true capabilities <- ["org.ek9.lang::Stdout"] defines function explainWhy() stdout <- Stdout() stdout.println("Capability declarations make supply chain attacks structurally visible.") stdout.println("When a new version declares org.ek9.lang::TCP, every consumer sees it before it runs.")
Other ways to ask this
- What problem does EK9 capability security solve?
- Why can't I just use any type in a published EK9 package?
- What supply chain attack does EK9 capability enforcement prevent?
- Explain the rationale for gated types in EK9.
Coming from another language?
npm (2015-2025): dozens of typosquatted and maintainer-hijack attacks; no capability model. PyPI (2022-2025): credential-stealing packages active for days before detection; no compile-time defence. Maven Central: no runtime permission enforcement beyond Java SecurityManager (deprecated). crates.io: safe Rust but no capability metadata. Go modules: no capability concept. EK9: compile-time capability enforcement at the module boundary — the compiler refuses to emit bytecode for undeclared gated type usage.
Keywords: security, supply chain, defence, gated type, rationale, capability, attack, why