Skip to content

Commit abd60cd

Browse files
authored
docs: clarify persist_uploaded_file folder is trusted app input (#1306)
Document that the folder/destination_folder argument of sqlpage.persist_uploaded_file must be chosen by the app author and never derived from untrusted request data. It is joined directly to the web root, so a value containing '..' or an absolute path would write the uploaded file outside the web root. Docs-only clarification of existing intended behavior; no logic change.
1 parent ada23bc commit abd60cd

2 files changed

Lines changed: 9 additions & 2 deletions

File tree

examples/official-site/sqlpage/migrations/39_persist_uploaded_file.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ VALUES (
5252
'persist_uploaded_file',
5353
2,
5454
'destination_folder',
55-
'Optional. Path to the folder where the file will be saved, relative to the web root (the root folder of your website files). By default, the file will be saved in the `uploads` folder.',
55+
'Optional. Path to the folder where the file will be saved, relative to the web root (the root folder of your website files). By default, the file will be saved in the `uploads` folder.
56+
57+
**Security note**: this value must be a folder name you choose yourself in your SQL code (a trusted constant). Never build it from untrusted input such as a form field, a query parameter, a request header, or anything else the visitor controls. The folder is joined directly to the web root, so a value containing `..` or an absolute path would cause the uploaded file to be written *outside* the web root, anywhere the SQLPage process can write. Keeping `destination_folder` a fixed value chosen by the application author avoids this.',
5658
'TEXT'
5759
),
5860
(

src/webserver/database/sqlpage_functions/functions.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,12 @@ async fn persist_uploaded_file<'a>(
512512
let exts = allowed_extensions.collect::<Vec<_>>().join(", ");
513513
anyhow::bail!("file extension {extension} is not allowed. Allowed extensions: {exts}");
514514
}
515-
// resolve the folder path relative to the web root
515+
// Resolve the folder path relative to the web root.
516+
// `folder` is trusted application input: it is expected to be a constant chosen by the
517+
// app author in their SQL code, never attacker-controlled request data. It is joined
518+
// directly to the web root, so a `folder` containing `..` or an absolute path would let
519+
// the caller write the uploaded file outside the web root. Callers must not pass
520+
// untrusted input (form fields, query parameters, headers, ...) as the folder.
516521
let web_root = &request.app_state.config.web_root;
517522
let target_folder = web_root.join(&*folder);
518523
// create the folder if it doesn't exist

0 commit comments

Comments
 (0)