From 84b03887a71eb0b742c6a2a85b5a172571a40f37 Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Fri, 5 Jun 2026 16:39:55 +0200 Subject: [PATCH] Document security policy and threat model --- SECURITY.md | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 912b9c8a2..a1e8cc60a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,6 +2,177 @@ ## Reporting a Vulnerability -If you find a critical security vulnerability in this repo, you can report it directly by -email to the main maintainer on `contact@ophir.dev`. -This will allow publishing a new safe version before the vulnerability starts being exploited. +Please report suspected SQLPage vulnerabilities privately to +`contact@ophir.dev`. + +Include the SQLPage version or commit, database backend, relevant +configuration, a minimal SQL file if possible, and the exact attacker-controlled +input. Do not open a public issue for a non-public vulnerability. + +## Threat Model + +SQLPage is a runtime for applications written in SQL. It maps HTTP requests to +SQL files, executes those files on the configured database, and renders the +result. SQLPage is not a sandbox for SQLPage application authors or operators. + +### Trusted Inputs + +SQLPage trusts the application and deployment: + +- application files under `web_root`; +- application files stored in the optional `sqlpage_files` table; +- configuration, command-line arguments, environment variables, and `.env` + files; +- templates, migrations, and connection-management SQL in the configuration + directory; +- database behavior and access: roles, permissions, schema, extensions, + triggers, stored procedures, views, and migrations; +- anyone or anything that can modify one of the above. + +Control of trusted inputs is control of the SQLPage application. If an attacker +can edit `sqlpage.json`, alter templates, change OIDC path rules, enable +dangerous Markdown options, enable `allow_exec`, or write SQL into +`sqlpage_files`, that is outside SQLPage's vulnerability boundary unless +SQLPage itself granted that access to an untrusted actor. + +### Untrusted Inputs + +SQLPage does not trust remote inputs: + +- HTTP paths, query strings, form fields, request bodies, and multipart uploads; +- uploaded filenames, MIME types, and file contents; +- HTTP headers, cookies, Basic Auth credentials, and unauthenticated OIDC + callback parameters; +- responses from remote servers contacted with `sqlpage.fetch` or + `sqlpage.fetch_with_meta`. + +Database row values are not classified globally as trusted or untrusted. +SQLPage cannot know whether a row came from an administrator-maintained table, +user-generated content, a trigger, or a third-party import. The security +boundary depends on where trusted SQL places the value. + +### Data Positions and Instruction Positions + +Trusted SQL chooses whether a value is ordinary data or an instruction to +SQLPage. + +Data positions are values SQLPage should render, serialize, encode, or pass as +bound database parameters without giving them extra authority. Examples include +ordinary table cells, text fields, JSON response data, CSV cells, and safe +Markdown. + +Instruction positions are values SQLPage intentionally treats as application +instructions or capability arguments. Examples include: + +- component names; +- `dynamic` component properties; +- response status codes, headers, redirects, cookies, and downloads; +- file paths passed to `run_sql`, `read_file_as_text`, or + `read_file_as_data_url`; +- URLs and request options passed to `fetch` or `fetch_with_meta`; +- raw HTML and unsafe Markdown; +- command names and arguments passed to `exec` when `allow_exec` is enabled. + +Placing a database value in an instruction position is an application decision. +For example, `select sqlpage.read_file_as_text(f) from trusted_table` is allowed +by design. If someone who can modify `trusted_table` can read arbitrary files, +that is a problem in the application or database permissions, not SQLPage. + +SQLPage's responsibility is to enforce the documented meaning and guardrails of +each position: data positions must not become instructions, instruction +positions must not bypass their documented checks, and malformed values must not +crash SQLPage or escape into unrelated capabilities. + +## In Scope + +Please report cases where SQLPage itself crosses that boundary. Examples: + +- An HTTP request can execute attacker-chosen SQL without trusted SQL explicitly + exposing that behavior. +- SQLPage parameter handling turns `$name`, `:name`, or `?name` into executable + SQL instead of a bound database value. +- A value in a data position causes SQL execution, command execution, host file + access, response-header injection, unsafe HTML execution, or another + instruction-position effect. +- A database value in any position reliably crashes or panics SQLPage instead + of producing a response or application-level error. +- HTTP routing, path decoding, static file serving, caching, `run_sql`, or file + functions expose host files that trusted SQL or configuration did not select. +- Reserved private files, including the `sqlpage/` prefix, dotfiles, + templates, and configuration, are reachable over HTTP. +- `allow_exec` is false, but an attacker can execute a local command through + SQLPage. +- Built-in OIDC handling accepts forged, expired, wrong-issuer, + wrong-audience, wrong-nonce, or wrong-signature tokens, or applies configured + public/protected path rules incorrectly. +- Default-safe rendering or safe Markdown executes browser script. +- SQLPage-generated production error responses expose source code, stack + traces, SQL text, parameters, environment values, or configuration values. +- Upload handling allows path traversal, overwrite of unintended files, or file + disclosure without trusted SQL selecting that behavior. +- Official SQLPage documentation or examples recommend placing untrusted remote + input into an instruction position without validation. + +## Out of Scope + +The following are usually application or deployment vulnerabilities, not +SQLPage vulnerabilities: + +- Trusted SQL omits authentication or authorization checks. +- Trusted SQL, a stored procedure, trigger, view, or extension builds and + executes SQL from untrusted data. +- Trusted SQL selects a value into an instruction position such as `component`, + `dynamic.properties`, a redirect target, header value, file path, `run_sql` + target, `fetch` URL, raw HTML, unsafe Markdown, or `exec` argument. +- Trusted SQL intentionally reads a host file, including an absolute path, and + returns it to a client. +- An operator intentionally changes configuration to expose files, trust a + different database, make an OIDC path public, weaken CSP, enable dangerous + Markdown options, load SQLite extensions, or enable `allow_exec`. +- An attacker can modify SQL files, templates, configuration, environment + variables, migrations, database code, or `sqlpage_files`. +- The configured database role has broader permissions than the application + needs. +- A SQLPage application is publicly reachable because no authentication was + configured. +- Trusted SQL asks SQLPage or the database to perform expensive work. + +These may still be serious and should be fixed in the affected application, +deployment, or documentation. + +## Boundary Examples + +Report: `/x.sql?sort=...` causes SQLPage to execute attacker-chosen SQL because +SQLPage rewrote a parameter incorrectly. + +Do not report as SQLPage: `x.sql` passes `sort` to a stored procedure that +concatenates it into dynamic SQL. + +Report: a normal table cell containing `