Passing the full host application instance to plugins — the Express app object, a raw database connection, or process — is functionally equivalent to giving every third-party plugin full administrative access to the application. Plugins can add routes, read or overwrite shared state, escalate their own permissions, or access data belonging to other plugins and tenants. OWASP A01 (Broken Access Control) and CWE-284 apply directly. The plugin surface becomes an attack surface: a malicious or compromised plugin can exfiltrate any data the host can reach.
Critical because exposing the full host instance to plugins grants third-party code unrestricted access to the database, internal state, and other plugins' data — OWASP A01 applied at the architecture level.
Replace full-instance passing with a scoped PluginContext that exposes only the APIs plugins legitimately need. Define the interface explicitly so the accessible surface is auditable.
interface PluginContext {
// Storage scoped to this plugin:
storage: PluginStorage;
// Only specific host APIs exposed:
hooks: HookRegistry;
config: Readonly<PluginConfig>;
logger: Logger;
// No access to: database, raw HTTP server, other plugins, internal state
}
ID: plugin-extension-architecture.isolation-security.resource-scoping
Severity: critical
What to look for: Check whether plugins receive a scoped API surface rather than access to the entire host application. Look for:
PluginContext or PluginAPI object passed to plugins that exposes only permitted methods — NOT the full host instanceExtensionContext with workspace-scoped storage, not full file system accessPass criteria: Count all resource allocation mechanisms per plugin. Plugins receive a scoped context or API object that limits their access to host internals. Plugins cannot directly access the database, file system (beyond designated paths), other plugins' state, or private host methods. The API surface available to plugins is explicitly defined. At least 1 scoping mechanism must exist (namespace, container, scope ID).
Fail criteria: Plugins receive the full host application instance (e.g., the Express app object, the raw database connection, the Node.js process object). Plugins can call any method, access any data, and modify any state without restriction.
Skip (N/A) when: The plugin system is designed for fully trusted first-party code only, the project is a personal tool with no third-party plugins, AND this trust model is explicitly documented.
Detail on fail: "Plugins receive the full Express app instance via plugin.init(app). They can add routes, modify middleware, access app.locals (shared state), and call app.listen(). There is no scoped API — plugins have the same access as the core application code."
Remediation: Resource scoping is what separates a plugin system from "just giving third-party code full access to your application." The scoped API should expose only what plugins need and nothing more.
// Scoped plugin context instead of full app:
interface PluginContext {
// Storage scoped to this plugin:
storage: PluginStorage;
// Only specific host APIs exposed:
hooks: HookRegistry;
config: Readonly<PluginConfig>;
logger: Logger;
// No access to: database, raw HTTP server, other plugins, internal state
}