|
2 | 2 |
|
3 | 3 | ## Reporting a Vulnerability |
4 | 4 |
|
5 | | -If you find a critical security vulnerability in this repo, you can report it directly by |
6 | | -email to the main maintainer on `contact@ophir.dev`. |
7 | | -This will allow publishing a new safe version before the vulnerability starts being exploited. |
| 5 | +Please report suspected SQLPage vulnerabilities privately to |
| 6 | +`contact@ophir.dev`. |
| 7 | + |
| 8 | +Include the SQLPage version or commit, database backend, relevant |
| 9 | +configuration, minimal SQL file if possible, and the exact attacker-controlled |
| 10 | +input. Do not open a public issue for a non-public vulnerability. |
| 11 | + |
| 12 | +## Threat Model |
| 13 | + |
| 14 | +SQLPage is a runtime for applications written in SQL. It maps HTTP requests to |
| 15 | +SQL files, executes those files on the configured database, and renders the |
| 16 | +result. SQLPage is not a sandbox for SQLPage application authors or operators. |
| 17 | + |
| 18 | +### Trusted Control |
| 19 | + |
| 20 | +The following define the application's behavior and are trusted: |
| 21 | + |
| 22 | +- Application files under `web_root`, including SQL files and static assets. |
| 23 | +- Application files stored in the optional `sqlpage_files` table. |
| 24 | +- SQLPage configuration, command-line arguments, environment variables, and |
| 25 | + `.env` files. |
| 26 | +- Templates, migrations, and connection-management SQL in the configuration |
| 27 | + directory. |
| 28 | +- Database behavior and access: roles, permissions, schema, extensions, |
| 29 | + triggers, stored procedures, views, and migrations. |
| 30 | +- Anyone or anything that can modify one of the above. |
| 31 | + |
| 32 | +Control of trusted inputs is control of the SQLPage application. If an attacker |
| 33 | +can edit `sqlpage.json`, change `web_root`, weaken OIDC path rules, enable |
| 34 | +dangerous Markdown options, enable `allow_exec`, alter templates, or write SQL |
| 35 | +into `sqlpage_files`, that is outside SQLPage's vulnerability boundary unless |
| 36 | +SQLPage itself granted that access to an untrusted actor. |
| 37 | + |
| 38 | +### Untrusted Data |
| 39 | + |
| 40 | +The following are untrusted data by default: |
| 41 | + |
| 42 | +- HTTP paths, query strings, form fields, request bodies, and multipart uploads. |
| 43 | +- Uploaded filenames, MIME types, and file contents. |
| 44 | +- HTTP headers, cookies, Basic Auth credentials, and unauthenticated OIDC |
| 45 | + callback parameters. |
| 46 | +- Responses from remote servers contacted with `sqlpage.fetch` or |
| 47 | + `sqlpage.fetch_with_meta`. |
| 48 | +- Values returned by database queries, except when SQLPage is loading |
| 49 | + application files from `sqlpage_files`. |
| 50 | + |
| 51 | +Database contents are data, not trust. A researcher should not have to prove |
| 52 | +which table values are user-generated. SQLPage must handle database values as |
| 53 | +untrusted unless trusted SQL places them in a documented control position. |
| 54 | + |
| 55 | +Some result columns are control positions: SQLPage treats their values as |
| 56 | +instructions, not ordinary display data. These include component names, |
| 57 | +`dynamic` component properties, HTTP headers, redirects, cookies, downloads, |
| 58 | +file paths passed to file functions or `run_sql`, URLs passed to `fetch`, raw |
| 59 | +HTML, unsafe Markdown, and `exec` command names or arguments. If trusted SQL |
| 60 | +puts untrusted data in a control position, the resulting behavior is the |
| 61 | +application's responsibility. |
| 62 | + |
| 63 | +## In Scope |
| 64 | + |
| 65 | +Please report cases where SQLPage itself lets untrusted data gain a capability |
| 66 | +that should require trusted control. Examples: |
| 67 | + |
| 68 | +- An HTTP request can execute attacker-chosen SQL on the configured database |
| 69 | + without trusted SQL explicitly exposing that behavior. |
| 70 | +- SQLPage parameter handling turns `$name`, `:name`, or `?name` into executable |
| 71 | + SQL instead of a bound database value. |
| 72 | +- HTTP routing, path decoding, static file serving, caching, `run_sql`, or file |
| 73 | + functions expose host files that trusted SQL or configuration did not choose |
| 74 | + to expose. |
| 75 | +- Reserved private files, including the `sqlpage/` prefix, dotfiles, |
| 76 | + templates, and configuration, are reachable over HTTP. |
| 77 | +- `allow_exec` is false, but an attacker can execute a local command through |
| 78 | + SQLPage. |
| 79 | +- Built-in OIDC handling accepts forged, expired, wrong-issuer, |
| 80 | + wrong-audience, wrong-nonce, or wrong-signature tokens, or applies configured |
| 81 | + public/protected path rules incorrectly. |
| 82 | +- Default-safe rendering or safe Markdown executes browser script from |
| 83 | + untrusted data. |
| 84 | +- SQLPage-generated production error responses expose source code, stack |
| 85 | + traces, SQL text, parameters, environment values, or configuration values. |
| 86 | +- Upload handling allows path traversal, overwrite of unintended files, or file |
| 87 | + disclosure without trusted SQL selecting that behavior. |
| 88 | +- Official SQLPage documentation or examples recommend placing untrusted data in |
| 89 | + a control position without validation. |
| 90 | + |
| 91 | +## Out of Scope |
| 92 | + |
| 93 | +The following are usually application or deployment vulnerabilities, not |
| 94 | +SQLPage vulnerabilities: |
| 95 | + |
| 96 | +- A trusted SQL file omits authentication or authorization checks. |
| 97 | +- Trusted SQL, a stored procedure, trigger, view, or extension builds and |
| 98 | + executes SQL from untrusted data. |
| 99 | +- Trusted SQL selects untrusted data into a control position such as |
| 100 | + `component`, `dynamic.properties`, a redirect target, header value, file path, |
| 101 | + `run_sql` target, `fetch` URL, raw HTML, unsafe Markdown, or `exec` argument. |
| 102 | +- Trusted SQL intentionally reads a host file, including an absolute path, and |
| 103 | + returns it to a client. |
| 104 | +- An operator intentionally changes configuration to expose files, trust a |
| 105 | + different database, make an OIDC path public, weaken CSP, enable dangerous |
| 106 | + Markdown options, load SQLite extensions, or enable `allow_exec`. |
| 107 | +- An attacker can modify SQL files, templates, configuration, environment |
| 108 | + variables, migrations, database code, or `sqlpage_files`. |
| 109 | +- The configured database role has broader permissions than the application |
| 110 | + needs. |
| 111 | +- A SQLPage application is publicly reachable because no authentication was |
| 112 | + configured. |
| 113 | +- Trusted SQL asks SQLPage or the database to perform expensive work. |
| 114 | + |
| 115 | +These may still be serious and should be fixed in the affected application, |
| 116 | +deployment, or documentation. |
| 117 | + |
| 118 | +## Boundary Examples |
| 119 | + |
| 120 | +Report: `/x.sql?sort=...` causes SQLPage to execute attacker-chosen SQL because |
| 121 | +SQLPage rewrote a parameter incorrectly. |
| 122 | + |
| 123 | +Do not report as SQLPage: `x.sql` passes `sort` to a stored procedure that |
| 124 | +concatenates it into dynamic SQL. |
| 125 | + |
| 126 | +Report: a normal table cell containing `<script>` executes script in the |
| 127 | +browser when rendered by a default-safe component. |
| 128 | + |
| 129 | +Do not report as SQLPage: trusted SQL selects that value as `html`, |
| 130 | +`unsafe_contents_md`, `component`, or `dynamic.properties`. |
| 131 | + |
| 132 | +Report: `/..%2F..%2Fetc%2Fpasswd` or `/sqlpage/sqlpage.json` is served directly |
| 133 | +by SQLPage. |
| 134 | + |
| 135 | +Do not report as SQLPage: trusted SQL calls |
| 136 | +`sqlpage.read_file_as_text('/etc/passwd')` and renders the result. |
| 137 | + |
| 138 | +Report: an unauthenticated request can write a new SQL file into |
| 139 | +`sqlpage_files` through an unintended SQLPage endpoint. |
| 140 | + |
| 141 | +Do not report as SQLPage: an administrator, migration, or intentionally exposed |
| 142 | +application page writes SQL into `sqlpage_files`. |
| 143 | + |
| 144 | +Report: official documentation recommends `sqlpage.run_sql($user_input)`. |
| 145 | + |
| 146 | +Do not report as SQLPage: a private application uses |
| 147 | +`sqlpage.run_sql($user_input)` despite the documentation warning against it. |
0 commit comments